firewatir 1.2.1 → 1.6.2

Sign up to get free protection for your applications and to get access to all the features.
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