firewatir 1.2.1 → 1.6.2

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 (47) hide show
  1. data/lib/firewatir.rb +50 -0
  2. data/lib/firewatir/MozillaBaseElement.rb +1863 -0
  3. data/lib/firewatir/container.rb +534 -0
  4. data/lib/firewatir/exceptions.rb +10 -0
  5. data/lib/firewatir/firefox.rb +1127 -0
  6. data/lib/firewatir/htmlelements.rb +1911 -0
  7. data/lib/firewatir/version.rb +5 -0
  8. data/{firewatir → lib/firewatir}/winClicker.rb +0 -0
  9. data/{firewatir → lib/firewatir}/x11.rb +0 -0
  10. data/unittests/attach_to_new_window_test.rb +20 -12
  11. data/unittests/bug_fixes_test.rb +79 -69
  12. data/unittests/buttons_xpath_test.rb +45 -44
  13. data/unittests/checkbox_test.rb +86 -85
  14. data/unittests/checkbox_xpath_test.rb +58 -58
  15. data/unittests/div_test.rb +117 -115
  16. data/unittests/filefield_test.rb +12 -12
  17. data/unittests/filefield_xpath_test.rb +11 -11
  18. data/unittests/form_test.rb +134 -133
  19. data/unittests/frame_test.rb +42 -41
  20. data/unittests/hidden_test.rb +40 -40
  21. data/unittests/hidden_xpath_test.rb +32 -32
  22. data/unittests/images_test.rb +85 -84
  23. data/unittests/images_xpath_test.rb +57 -56
  24. data/unittests/iostring_test.rb +1 -1
  25. data/unittests/javascript_test.rb +42 -38
  26. data/unittests/links_test.rb +88 -86
  27. data/unittests/links_xpath_test.rb +38 -38
  28. data/unittests/mozilla_all_tests.rb +2 -14
  29. data/unittests/pre_test.rb +27 -25
  30. data/unittests/radios_test.rb +86 -86
  31. data/unittests/radios_xpath_test.rb +48 -48
  32. data/unittests/redirect_test.rb +20 -19
  33. data/unittests/selectbox_test.rb +72 -71
  34. data/unittests/selectbox_xpath_test.rb +58 -56
  35. data/unittests/setup.rb +22 -27
  36. data/unittests/table_test.rb +89 -88
  37. data/unittests/table_xpath_test.rb +37 -36
  38. data/unittests/textfields_test.rb +105 -102
  39. data/unittests/textfields_xpath_test.rb +53 -52
  40. metadata +37 -18
  41. data/MozillaBaseElement.rb +0 -1780
  42. data/container.rb +0 -900
  43. data/firewatir.rb +0 -1195
  44. data/firewatir/exceptions.rb +0 -44
  45. data/firewatir/testUnitAddons.rb +0 -8
  46. data/htmlelements.rb +0 -2281
  47. data/unittests/buttons_test.rb +0 -215
data/firewatir.rb DELETED
@@ -1,1195 +0,0 @@
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
-
259
- # Derek Berner 5/16/08
260
- # If at any time a non-browser window like the "Downloads" window
261
- # pops up, it will become the topmost window, so make sure we
262
- # ignore it.
263
- @@current_window = js_eval("getWindows().length").to_i - 1
264
- while js_eval("getWindows()[#{@@current_window}].getBrowser") == ''
265
- @@current_window -= 1;
266
- end
267
-
268
- # This will store the information about the window.
269
- #@@window_stack.push(@@current_window)
270
- #puts "here in get_window_number window number is #{@@current_window}"
271
- return @@current_window
272
- end
273
- private :get_window_number
274
-
275
- #
276
- # Description:
277
- # Loads the given url in the browser. Waits for the page to get loaded.
278
- #
279
- # Input:
280
- # url - url to be loaded.
281
- #
282
- def goto(url)
283
- #set_defaults()
284
- get_window_number()
285
- set_browser_document()
286
- # Load the given url.
287
- $jssh_socket.send("#{BROWSER_VAR}.loadURI(\"#{url}\");\n" , 0)
288
- read_socket()
289
-
290
- wait()
291
- end
292
-
293
- #
294
- # Description:
295
- # Loads the previous page (if there is any) in the browser. Waits for the page to get loaded.
296
- #
297
- def back()
298
- #set_browser_document()
299
- $jssh_socket.send("if(#{BROWSER_VAR}.canGoBack) #{BROWSER_VAR}.goBack();\n", 0)
300
- read_socket();
301
- wait()
302
- end
303
-
304
- #
305
- # Description:
306
- # Loads the next page (if there is any) in the browser. Waits for the page to get loaded.
307
- #
308
- def forward()
309
- #set_browser_document()
310
- $jssh_socket.send("if(#{BROWSER_VAR}.canGoForward) #{BROWSER_VAR}.goForward();\n", 0)
311
- read_socket();
312
- wait()
313
- end
314
-
315
- #
316
- # Description:
317
- # Reloads the current page in the browser. Waits for the page to get loaded.
318
- #
319
- def refresh()
320
- #set_browser_document()
321
- $jssh_socket.send("#{BROWSER_VAR}.reload();\n", 0)
322
- read_socket();
323
- wait()
324
- end
325
-
326
- #
327
- # Description:
328
- # This function creates a new socket at port 9997 and sets the default values for instance and class variables.
329
- # Generatesi UnableToStartJSShException if cannot connect to jssh even after 3 tries.
330
- #
331
- def set_defaults(no_of_tries = 0)
332
- # JSSH listens on port 9997. Create a new socket to connect to port 9997.
333
- begin
334
- $jssh_socket = TCPSocket::new(MACHINE_IP, "9997")
335
- $jssh_socket.sync = true
336
- read_socket()
337
- rescue
338
- no_of_tries += 1
339
- retry if no_of_tries < 3
340
- 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"
341
- end
342
- @error_checkers = []
343
- end
344
- private :set_defaults
345
-
346
- def set_slow_speed
347
- @typingspeed = DEFAULT_TYPING_SPEED
348
- @defaultSleepTime = DEFAULT_SLEEP_TIME
349
- end
350
- private :set_slow_speed
351
-
352
- #
353
- # Description:
354
- # Sets the document, window and browser variables to point to correct object in JSSh.
355
- #
356
- def set_browser_document
357
- # Get the window in variable WINDOW_VAR.
358
- # Get the browser in variable BROWSER_VAR.
359
- jssh_command = "var #{WINDOW_VAR} = getWindows()[#{@@current_window}];"
360
- jssh_command += " var #{BROWSER_VAR} = #{WINDOW_VAR}.getBrowser();"
361
- # Get the document and body in variable DOCUMENT_VAR and BODY_VAR respectively.
362
- jssh_command += "var #{DOCUMENT_VAR} = #{BROWSER_VAR}.contentDocument;"
363
- jssh_command += "var #{BODY_VAR} = #{DOCUMENT_VAR}.body;"
364
-
365
- $jssh_socket.send("#{jssh_command}\n", 0)
366
- read_socket()
367
-
368
- # Get window and window's parent title and url
369
- $jssh_socket.send("#{DOCUMENT_VAR}.title;\n", 0)
370
- @window_title = read_socket()
371
- $jssh_socket.send("#{DOCUMENT_VAR}.URL;\n", 0)
372
- @window_url = read_socket()
373
- end
374
- private :set_browser_document
375
-
376
- #
377
- # Description:
378
- # Closes the window.
379
- #
380
- def close()
381
- #puts "current window number is : #{@@current_window}"
382
- # Derek Berner 5/16/08
383
- # Try to join thread only if there is exactly one open window
384
- if js_eval("getWindows().length").to_i == 1
385
- $jssh_socket.send(" getWindows()[0].close(); \n", 0)
386
- @t.join if @t != nil
387
- #sleep 5
388
- else
389
- # Check if window exists, because there may be the case that it has been closed by click event on some element.
390
- # For e.g: Close Button, Close this Window link etc.
391
- window_number = find_window("url", @window_url)
392
-
393
- # If matching window found. Close the window.
394
- if(window_number > 0)
395
- $jssh_socket.send(" getWindows()[#{window_number}].close();\n", 0)
396
- read_socket();
397
- end
398
-
399
- #Get the parent window url from the stack and return that window.
400
- #@@current_window = @@window_stack.pop()
401
- @window_url = @@window_stack.pop()
402
- @window_title = @@window_stack.pop()
403
- # Find window with this url.
404
- window_number = find_window("url", @window_url)
405
- @@current_window = window_number
406
- set_browser_document()
407
- end
408
- end
409
-
410
- #
411
- # Description:
412
- # Used for attaching pop up window to an existing Firefox window, either by url or title.
413
- # ff.attach(:url, 'http://www.google.com')
414
- # ff.attach(:title, 'Google')
415
- #
416
- # Output:
417
- # Instance of newly attached window.
418
- #
419
- def attach(how, what)
420
- window_number = find_window(how, what)
421
-
422
- if(window_number == 0)
423
- raise NoMatchingWindowFoundException.new("Unable to locate window, using #{how} and #{what}")
424
- elsif(window_number > 0)
425
- # Push the window_title and window_url of parent window. So that when we close the child window
426
- # appropriate handle of parent window is returned back.
427
- @@window_stack.push(@window_title)
428
- @@window_stack.push(@window_url)
429
-
430
- @@current_window = window_number.to_i
431
- set_browser_document()
432
- end
433
- self
434
- end
435
-
436
- #
437
- # Description:
438
- # Finds a Firefox browser window with a given title or url.
439
- #
440
- def find_window(how, what)
441
- jssh_command = "getWindows().length;";
442
- $jssh_socket.send("#{jssh_command}\n", 0)
443
- @@total_windows = read_socket()
444
- #puts "total windows are : " + @@total_windows.to_s
445
-
446
- jssh_command = "var windows = getWindows(); var window_number = 0;var found = false;
447
- for(var i = 0; i < windows.length; i++)
448
- {
449
- var attribute = '';
450
- if(\"#{how}\" == \"url\")
451
- {
452
- attribute = windows[i].getBrowser().contentDocument.URL;
453
- }
454
- if(\"#{how}\" == \"title\")
455
- {
456
- attribute = windows[i].getBrowser().contentDocument.title;
457
- }"
458
- if(what.class == Regexp)
459
- # Construct the regular expression because we can't use it directly by converting it to string.
460
- # If reg ex is /Google/i then its string conversion will be (?i-mx:Google) so we can't use it.
461
- # Construct the regular expression again from the string conversion.
462
- oldRegExp = what.to_s
463
- newRegExp = "/" + what.source + "/"
464
- flags = oldRegExp.slice(2, oldRegExp.index(':') - 2)
465
-
466
- for i in 0..flags.length do
467
- flag = flags[i, 1]
468
- if(flag == '-')
469
- break;
470
- else
471
- newRegExp << flag
472
- end
473
- end
474
-
475
- jssh_command += "var regExp = new RegExp(#{newRegExp});
476
- found = regExp.test(attribute);"
477
- else
478
- jssh_command += "found = (attribute == \"#{what}\");"
479
- end
480
-
481
- jssh_command += "if(found)
482
- {
483
- window_number = i;
484
- break;
485
- }
486
- }
487
- window_number;"
488
-
489
- jssh_command.gsub!(/\n/, "")
490
- #puts "jssh_command is : #{jssh_command}"
491
- $jssh_socket.send("#{jssh_command}\n", 0)
492
- window_number = read_socket()
493
- #puts "window number is : " + window_number.to_s
494
-
495
- return window_number.to_i
496
- end
497
- private :find_window
498
-
499
- #
500
- # Description:
501
- # Matches the given text with the current text shown in the browser.
502
- #
503
- # Input:
504
- # target - Text to match. Can be a string or regex
505
- #
506
- # Output:
507
- # Returns the index if the specified text was found.
508
- # Returns matchdata object if the specified regexp was found.
509
- #
510
- def contains_text(target)
511
- #puts "Text to match is : #{match_text}"
512
- #puts "Html is : #{self.text}"
513
- if target.kind_of? Regexp
514
- self.text.match(target)
515
- elsif target.kind_of? String
516
- self.text.index(target)
517
- else
518
- raise ArgumentError, "Argument #{target} should be a string or regexp."
519
- end
520
- end
521
-
522
- #
523
- # Description:
524
- # Returns the url of the page currently loaded in the browser.
525
- #
526
- # Output:
527
- # URL of the page.
528
- #
529
- def url()
530
- @window_url
531
- end
532
-
533
- #
534
- # Description:
535
- # Returns the title of the page currently loaded in the browser.
536
- #
537
- # Output:
538
- # Title of the page.
539
- #
540
- def title()
541
- @window_title
542
- end
543
-
544
- #
545
- # Description:
546
- # Returns the html of the page currently loaded in the browser.
547
- #
548
- # Output:
549
- # HTML shown on the page.
550
- #
551
- def html()
552
- $jssh_socket.send("var htmlelem = #{DOCUMENT_VAR}.getElementsByTagName('html')[0]; htmlelem.innerHTML;\n", 0)
553
- #$jssh_socket.send("#{BODY_VAR}.innerHTML;\n", 0)
554
- result = read_socket()
555
- return "<html>" + result + "</html>"
556
- end
557
-
558
- #
559
- # Description:
560
- # Returns the text of the page currently loaded in the browser.
561
- #
562
- # Output:
563
- # Text shown on the page.
564
- #
565
- def text()
566
- $jssh_socket.send("#{BODY_VAR}.textContent;\n", 0)
567
- return read_socket().strip
568
- end
569
-
570
- #
571
- # Description:
572
- # Maximize the current browser window.
573
- #
574
- def maximize()
575
- $jssh_socket.send("#{WINDOW_VAR}.maximize();\n", 0)
576
- read_socket()
577
- end
578
-
579
- #
580
- # Description:
581
- # Minimize the current browser window.
582
- #
583
- def minimize()
584
- $jssh_socket.send("#{WINDOW_VAR}.minimize();\n", 0)
585
- read_socket()
586
- end
587
-
588
- #
589
- # Description:
590
- # Waits for the page to get loaded.
591
- #
592
- def wait(last_url = nil)
593
- #puts "In wait function "
594
- isLoadingDocument = ""
595
- start = Time.now
596
-
597
- while isLoadingDocument != "false"
598
- isLoadingDocument = js_eval("#{BROWSER_VAR}=#{WINDOW_VAR}.getBrowser(); #{BROWSER_VAR}.webProgress.isLoadingDocument;")
599
- #puts "Is browser still loading page: #{isLoadingDocument}"
600
-
601
- # Derek Berner 5/16/08
602
- # Raise an exception if the page fails to load
603
- if (Time.now - start) > 300
604
- raise "Page Load Timeout"
605
- end
606
- end
607
- # Derek Berner 5/16/08
608
- # If the redirect is to a download attachment that does not reload this page, this
609
- # method will loop forever. Therefore, we need to ensure that if this method is called
610
- # twice with the same URL, we simply accept that we're done.
611
- $jssh_socket.send("#{BROWSER_VAR}.contentDocument.URL;\n", 0)
612
- url = read_socket()
613
-
614
- if(url != last_url)
615
- # Check for Javascript redirect. As we are connected to Firefox via JSSh. JSSh
616
- # doesn't detect any javascript redirects so check it here.
617
- # If page redirects to itself that this code will enter in infinite loop.
618
- # So we currently don't wait for such a page.
619
- # wait variable in JSSh tells if we should wait more for the page to get loaded
620
- # or continue. -1 means page is not redirected. Anyother positive values means wait.
621
- jssh_command = "var wait = -1; var meta = null; meta = #{BROWSER_VAR}.contentDocument.getElementsByTagName('meta');
622
- if(meta != null)
623
- {
624
- var doc_url = #{BROWSER_VAR}.contentDocument.URL;
625
- for(var i=0; i< meta.length;++i)
626
- {
627
- var content = meta[i].content;
628
- var regex = new RegExp(\"^refresh$\", \"i\");
629
- if(regex.test(meta[i].httpEquiv))
630
- {
631
- var arrContent = content.split(';');
632
- var redirect_url = null;
633
- if(arrContent.length > 0)
634
- {
635
- if(arrContent.length > 1)
636
- redirect_url = arrContent[1];
637
-
638
- if(redirect_url != null)
639
- {
640
- regex = new RegExp(\"^.*\" + redirect_url + \"$\");
641
- if(!regex.test(doc_url))
642
- {
643
- wait = arrContent[0];
644
- }
645
- }
646
- break;
647
- }
648
- }
649
- }
650
- }
651
- wait;"
652
- #puts "command in wait is : #{jssh_command}"
653
- jssh_command = jssh_command.gsub(/\n/, "")
654
- $jssh_socket.send("#{jssh_command}; \n", 0)
655
- wait_time = read_socket();
656
- #puts "wait time is : #{wait_time}"
657
- begin
658
- wait_time = wait_time.to_i
659
- if(wait_time != -1)
660
- sleep(wait_time)
661
- # Call wait again. In case there are multiple redirects.
662
- $jssh_socket.send("#{BROWSER_VAR} = #{WINDOW_VAR}.getBrowser(); \n",0)
663
- read_socket()
664
- wait(url)
665
- end
666
- rescue
667
- end
668
- end
669
- set_browser_document()
670
- run_error_checks()
671
- return self
672
- end
673
-
674
- # Add an error checker that gets called on every page load.
675
- #
676
- # * checker - a Proc object
677
- def add_checker(checker)
678
- @error_checkers << checker
679
- end
680
-
681
- # Disable an error checker
682
- #
683
- # * checker - a Proc object that is to be disabled
684
- def disable_checker(checker)
685
- @error_checkers.delete(checker)
686
- end
687
-
688
- # Run the predefined error checks. This is automatically called on every page load.
689
- def run_error_checks
690
- @error_checkers.each { |e| e.call(self) }
691
- end
692
-
693
-
694
- #def jspopup_appeared(popupText = "", wait = 2)
695
- # winHelper = WindowHelper.new()
696
- # return winHelper.hasPopupAppeared(popupText, wait)
697
- #end
698
-
699
- #
700
- # Description:
701
- # Redefines the alert and confirm methods on the basis of button to be clicked.
702
- # This is done so that JSSh doesn't get blocked. You should use click_no_wait method before calling this function.
703
- #
704
- # Typical Usage:
705
- # ff.button(:id, "button").click_no_wait
706
- # ff.click_jspopup_button("OK")
707
- #
708
- # Input:
709
- # button - JavaScript button to be clicked. Values can be OK or Cancel
710
- #
711
- #def click_jspopup_button(button)
712
- # button = button.downcase
713
- # element = Element.new(nil)
714
- # element.click_js_popup(button)
715
- #end
716
-
717
- #
718
- # Description:
719
- # Tells FireWatir to click javascript button in case one comes after performing some action on an element. Matches
720
- # text of pop up with one if supplied as parameter. If text matches clicks the button else stop script execution until
721
- # pop up is dismissed by manual intervention.
722
- #
723
- # Input:
724
- # button - JavaScript button to be clicked. Values can be OK or Cancel
725
- # waitTime - Time to wait for pop up to come. Not used just for compatibility with Watir.
726
- # userInput - Not used just for compatibility with Watir
727
- # text - Text that should appear on pop up.
728
- #
729
- def startClicker(button, waitTime = 1, userInput = nil, text = nil)
730
- jssh_command = "var win = #{BROWSER_VAR}.contentWindow;"
731
- if(button =~ /ok/i)
732
- jssh_command += "var popuptext = '';
733
- var old_alert = win.alert;
734
- var old_confirm = win.confirm;
735
- win.alert = function(param) {"
736
- if(text != nil)
737
- jssh_command += "if(param == \"#{text}\") {
738
- popuptext = param;
739
- return true;
740
- }
741
- else {
742
- popuptext = param;
743
- win.alert = old_alert;
744
- win.alert(param);
745
- }"
746
- else
747
- jssh_command += "popuptext = param; return true;"
748
- end
749
- jssh_command += "};
750
- win.confirm = function(param) {"
751
- if(text != nil)
752
- jssh_command += "if(param == \"#{text}\") {
753
- popuptext = param;
754
- return true;
755
- }
756
- else {
757
- win.confirm = old_confirm;
758
- win.confirm(param);
759
- }"
760
- else
761
- jssh_command += "popuptext = param; return true;"
762
- end
763
- jssh_command += "};"
764
-
765
- elsif(button =~ /cancel/i)
766
- jssh_command = "var old_confirm = win.confirm;
767
- win.confirm = function(param) {"
768
- if(text != nil)
769
- jssh_command += "if(param == \"#{text}\") {
770
- popuptext = param;
771
- return false;
772
- }
773
- else {
774
- win.confirm = old_confirm;
775
- win.confirm(param);
776
- }"
777
- else
778
- jssh_command += "popuptext = param; return false;"
779
- end
780
- jssh_command += "};"
781
- end
782
- jssh_command.gsub!(/\n/, "")
783
- #puts "jssh command sent for js pop up is : #{jssh_command}"
784
- $jssh_socket.send("#{jssh_command}\n", 0)
785
- read_socket()
786
- end
787
-
788
- #
789
- # Description:
790
- # Returns text of javascript pop up in case it comes.
791
- #
792
- # Output:
793
- # Text shown in javascript pop up.
794
- #
795
- def get_popup_text()
796
- $jssh_socket.send("popuptext;\n", 0)
797
- return_value = read_socket()
798
- # reset the variable
799
- $jssh_socket.send("popuptext = '';\n", 0)
800
- read_socket()
801
- return return_value
802
- end
803
-
804
- #
805
- # Description:
806
- # Returns the document element of the page currently loaded in the browser.
807
- #
808
- # Output:
809
- # Document element.
810
- #
811
- def document
812
- Document.new("#{DOCUMENT_VAR}")
813
- end
814
-
815
- #
816
- # Description:
817
- # Returns the first element that matches the xpath query.
818
- #
819
- # Input:
820
- # Xpath expression or query.
821
- #
822
- # Output:
823
- # Element matching the xpath query.
824
- #
825
- def element_by_xpath(xpath)
826
- temp = Element.new(nil, self)
827
- element_name = temp.element_by_xpath(self, xpath)
828
- return element_factory(element_name)
829
- end
830
-
831
- #
832
- # Description:
833
- # Factory method to create object of correct Element class while using XPath to get the element.
834
- #
835
- def element_factory(element_name)
836
- jssh_type = Element.new(element_name,self).element_type
837
- #puts "jssh type is : #{jssh_type}" # DEBUG
838
- candidate_class = jssh_type =~ /HTML(.*)Element/ ? $1 : ''
839
- #puts candidate_class # DEBUG
840
- if candidate_class == 'Input'
841
- $jssh_socket.send("#{element_name}.type;\n", 0)
842
- input_type = read_socket().downcase.strip
843
- puts input_type # DEBUG
844
- firewatir_class = input_class(input_type)
845
- else
846
- firewatir_class = jssh2firewatir(candidate_class)
847
- end
848
-
849
- #puts firewatir_class # DEBUG
850
- klass = Kernel.const_get(firewatir_class)
851
-
852
- if klass == Element
853
- klass.new(element_name,self)
854
- elsif klass == CheckBox
855
- klass.new(self,:jssh_name,element_name,["checkbox"])
856
- elsif klass == Radio
857
- klass.new(self,:jssh_name,element_name,["radio"])
858
- else
859
- klass.new(self,:jssh_name,element_name)
860
- end
861
- end
862
- private :element_factory
863
-
864
- #
865
- # Description:
866
- # Get the class name for element of input type depending upon its type like checkbox, radio etc.
867
- #
868
- def input_class(input_type)
869
- hash = {
870
- 'select-one' => 'SelectList',
871
- 'select-multiple' => 'SelectList',
872
- 'text' => 'TextField',
873
- 'password' => 'TextField',
874
- 'textarea' => 'TextField',
875
- # TODO when there's no type, it's a TextField
876
- 'file' => 'FileField',
877
- 'checkbox' => 'CheckBox',
878
- 'radio' => 'Radio',
879
- 'reset' => 'Button',
880
- 'button' => 'Button',
881
- 'submit' => 'Button',
882
- 'image' => 'Button'
883
- }
884
- hash.default = 'Element'
885
-
886
- hash[input_type]
887
- end
888
- private :input_class
889
-
890
- #
891
- # Description:
892
- # Converts element type returned by JSSh like HTMLDivElement to its corresponding class in Firewatir.
893
- #
894
- def jssh2firewatir(candidate_class)
895
- hash = {
896
- 'Div' => 'Div',
897
- 'Button' => 'Button',
898
- 'Frame' => 'Frame',
899
- 'Span' => 'Span',
900
- 'Paragraph' => 'P',
901
- 'Label' => 'Label',
902
- 'Form' => 'Form',
903
- 'Image' => 'Image',
904
- 'Table' => 'Table',
905
- 'TableCell' => 'TableCell',
906
- 'TableRow' => 'TableRow',
907
- 'Select' => 'SelectList',
908
- 'Link' => 'Link',
909
- 'Anchor' => 'Link' # FIXME is this right?
910
- #'Option' => 'Option' #Option uses a different constructor
911
- }
912
- hash.default = 'Element'
913
- hash[candidate_class]
914
- end
915
- private :jssh2firewatir
916
-
917
- #
918
- # Description:
919
- # Returns the array of elements that matches the xpath query.
920
- #
921
- # Input:
922
- # Xpath expression or query.
923
- #
924
- # Output:
925
- # Array of elements matching xpath query.
926
- #
927
- def elements_by_xpath(xpath)
928
- element = Element.new(nil, self)
929
- elem_names = element.elements_by_xpath(self, xpath)
930
- a = elem_names.inject([]) {|elements,name| elements << element_factory(name)}
931
- end
932
-
933
- #
934
- # Description:
935
- # Show all the forms available on the page.
936
- #
937
- # Output:
938
- # Name, id, method and action of all the forms available on the page.
939
- #
940
- def show_forms
941
- forms = Document.new(self).get_forms()
942
- count = forms.length
943
- puts "There are #{count} forms"
944
- for i in 0..count - 1 do
945
- puts "Form name: " + forms[i].name
946
- puts " id: " + forms[i].id
947
- puts " method: " + forms[i].attribute_value("method")
948
- puts " action: " + forms[i].action
949
- end
950
- end
951
- alias showForms show_forms
952
-
953
- #
954
- # Description:
955
- # Show all the images available on the page.
956
- #
957
- # Output:
958
- # Name, id, src and index of all the images available on the page.
959
- #
960
- def show_images
961
- images = Document.new(self).get_images
962
- puts "There are #{images.length} images"
963
- index = 1
964
- images.each do |l|
965
- puts "image: name: #{l.name}"
966
- puts " id: #{l.id}"
967
- puts " src: #{l.src}"
968
- puts " index: #{index}"
969
- index += 1
970
- end
971
- end
972
- alias showImages show_images
973
-
974
- #
975
- # Description:
976
- # Show all the links available on the page.
977
- #
978
- # Output:
979
- # Name, id, href and index of all the links available on the page.
980
- #
981
- def show_links
982
- links = Document.new(self).get_links
983
- puts "There are #{links.length} links"
984
- index = 1
985
- links.each do |l|
986
- puts "link: name: #{l.name}"
987
- puts " id: #{l.id}"
988
- puts " href: #{l.href}"
989
- puts " index: #{index}"
990
- index += 1
991
- end
992
- end
993
- alias showLinks show_links
994
-
995
- #
996
- # Description:
997
- # Show all the divs available on the page.
998
- #
999
- # Output:
1000
- # Name, id, class and index of all the divs available on the page.
1001
- #
1002
- def show_divs
1003
- divs = Document.new(self).get_divs
1004
- puts "There are #{divs.length} divs"
1005
- index = 1
1006
- divs.each do |l|
1007
- puts "div: name: #{l.name}"
1008
- puts " id: #{l.id}"
1009
- puts " class: #{l.className}"
1010
- puts " index: #{index}"
1011
- index += 1
1012
- end
1013
- end
1014
- alias showDivs show_divs
1015
-
1016
- #
1017
- # Description:
1018
- # Show all the tables available on the page.
1019
- #
1020
- # Output:
1021
- # Id, row count, column count (only first row) and index of all the tables available on the page.
1022
- #
1023
- def show_tables
1024
- tables = Document.new(self).get_tables
1025
- puts "There are #{tables.length} tables"
1026
- index = 1
1027
- tables.each do |l|
1028
- puts "table: id: #{l.id}"
1029
- puts " rows: #{l.row_count}"
1030
- puts " columns: #{l.column_count}"
1031
- puts " index: #{index}"
1032
- index += 1
1033
- end
1034
- end
1035
- alias showTables show_tables
1036
-
1037
- #
1038
- # Description:
1039
- # Show all the pre elements available on the page.
1040
- #
1041
- # Output:
1042
- # Id, name and index of all the pre elements available on the page.
1043
- #
1044
- def show_pres
1045
- pres = Document.new(self).get_pres
1046
- puts "There are #{pres.length} pres"
1047
- index = 1
1048
- pres.each do |l|
1049
- puts "pre: id: #{l.id}"
1050
- puts " name: #{l.name}"
1051
- puts " index: #{index}"
1052
- index += 1
1053
- end
1054
- end
1055
- alias showPres show_pres
1056
-
1057
- #
1058
- # Description:
1059
- # Show all the spans available on the page.
1060
- #
1061
- # Output:
1062
- # Name, id, class and index of all the spans available on the page.
1063
- #
1064
- def show_spans
1065
- spans = Document.new(self).get_spans
1066
- puts "There are #{spans.length} spans"
1067
- index = 1
1068
- spans.each do |l|
1069
- puts "span: name: #{l.name}"
1070
- puts " id: #{l.id}"
1071
- puts " class: #{l.className}"
1072
- puts " index: #{index}"
1073
- index += 1
1074
- end
1075
- end
1076
- alias showSpans show_spans
1077
-
1078
- #
1079
- # Description:
1080
- # Show all the labels available on the page.
1081
- #
1082
- # Output:
1083
- # Name, id, for and index of all the labels available on the page.
1084
- #
1085
- def show_labels
1086
- labels = Document.new(self).get_labels
1087
- puts "There are #{labels.length} labels"
1088
- index = 1
1089
- labels.each do |l|
1090
- puts "label: name: #{l.name}"
1091
- puts " id: #{l.id}"
1092
- puts " for: #{l.for}"
1093
- puts " index: #{index}"
1094
- index += 1
1095
- end
1096
- end
1097
- alias showLabels show_labels
1098
-
1099
- #
1100
- # Description:
1101
- # Show all the frames available on the page. Doesn't show nested frames.
1102
- #
1103
- # Output:
1104
- # Name, and index of all the frames available on the page.
1105
- #
1106
- def show_frames
1107
- jssh_command = "var frameset = #{WINDOW_VAR}.frames;
1108
- var elements_frames = new Array();
1109
- for(var i = 0; i < frameset.length; i++)
1110
- {
1111
- var frames = frameset[i].frames;
1112
- for(var j = 0; j < frames.length; j++)
1113
- {
1114
- elements_frames.push(frames[j].frameElement);
1115
- }
1116
- }
1117
- elements_frames.length;"
1118
-
1119
- jssh_command.gsub!("\n", "")
1120
- $jssh_socket.send("#{jssh_command};\n", 0)
1121
- length = read_socket().to_i
1122
-
1123
- puts "There are #{length} frames"
1124
-
1125
- frames = Array.new(length)
1126
- for i in 0..length - 1 do
1127
- frames[i] = Frame.new(self, :jssh_name, "elements_frames[#{i}]")
1128
- end
1129
-
1130
- for i in 0..length - 1 do
1131
- puts "frame: name: #{frames[i].name}"
1132
- puts " index: #{i+1}"
1133
- end
1134
- end
1135
- alias showFrames show_frames
1136
-
1137
- # 5/16/08 Derek Berner
1138
- # Wrapper method to send JS commands concisely,
1139
- # and propagate errors
1140
- def js_eval(str)
1141
- #puts "JS Eval: #{str}"
1142
- $jssh_socket.send("#{str};\n",0)
1143
- value = read_socket()
1144
- if md=/^(\w+)Error:(.*)$/.match(value)
1145
- eval "class JS#{md[1]}Error\nend"
1146
- raise (eval "JS#{md[1]}Error"), md[2]
1147
- end
1148
- #puts "Value: #{value}"
1149
- value
1150
- end
1151
-
1152
- end # Class Firefox
1153
-
1154
- #
1155
- # Module for handling the Javascript pop-ups. Not in use currently, will be available in future.
1156
- # Use ff.startClicker() method for clicking javascript pop ups. Refer to unit tests on how to handle
1157
- # javascript pop up (unittests/javascript_test.rb)
1158
- #module Dialog
1159
- # # Class for handling javascript popup. Not in use currently, will be available in future. See unit tests on how to handle
1160
- # # javascript pop up (unittests/javascript_test.rb).
1161
- # class JSPopUp
1162
- # include Container
1163
- #
1164
- # def has_appeared(text)
1165
- # require 'socket'
1166
- # sleep 4
1167
- # shell = TCPSocket.new("localhost", 9997)
1168
- # read_socket(shell)
1169
- # #jssh_command = "var url = #{DOCUMENT_VAR}.URL;"
1170
- # jssh_command = "var length = getWindows().length; var win;length;\n"
1171
- # #jssh_command += "for(var i = 0; i < length; i++)"
1172
- # #jssh_command += "{"
1173
- # #jssh_command += " win = getWindows()[i];"
1174
- # #jssh_command += " if(win.opener != null && "
1175
- # #jssh_command += " win.title == \"[JavaScript Application]\" &&"
1176
- # #jssh_command += " win.opener.document.URL == url)"
1177
- # #jssh_command += " {"
1178
- # #jssh_command += " break;"
1179
- # #jssh_command += " }"
1180
- # #jssh_command += "}"
1181
- #
1182
- # #jssh_command += " win.title;\n";
1183
- # #jssh_command += "var dialog = win.document.childNodes[0];"
1184
- # #jssh_command += "vbox = dialog.childNodes[1].childNodes[1];"
1185
- # #jssh_command += "vbox.childNodes[1].childNodes[0].childNodes[0].textContent;\n"
1186
- # puts jssh_command
1187
- # shell.send("#{jssh_command}", 0)
1188
- # jstext = read_socket(shell)
1189
- # puts jstext
1190
- # return jstext == text
1191
- # end
1192
- # end
1193
- #end
1194
-
1195
- end