mk_firewatir 1.6.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. data/LICENSE +32 -0
  2. data/lib/firewatir.rb +41 -0
  3. data/lib/firewatir/container.rb +491 -0
  4. data/lib/firewatir/document.rb +239 -0
  5. data/lib/firewatir/element.rb +1369 -0
  6. data/lib/firewatir/element_collections.rb +314 -0
  7. data/lib/firewatir/elements/button.rb +15 -0
  8. data/lib/firewatir/elements/file_field.rb +29 -0
  9. data/lib/firewatir/elements/form.rb +40 -0
  10. data/lib/firewatir/elements/frame.rb +55 -0
  11. data/lib/firewatir/elements/hidden.rb +56 -0
  12. data/lib/firewatir/elements/image.rb +139 -0
  13. data/lib/firewatir/elements/input_element.rb +44 -0
  14. data/lib/firewatir/elements/link.rb +76 -0
  15. data/lib/firewatir/elements/non_control_element.rb +53 -0
  16. data/lib/firewatir/elements/non_control_elements.rb +108 -0
  17. data/lib/firewatir/elements/not_used.rb +278 -0
  18. data/lib/firewatir/elements/option.rb +131 -0
  19. data/lib/firewatir/elements/radio_check_common.rb +163 -0
  20. data/lib/firewatir/elements/select_list.rb +188 -0
  21. data/lib/firewatir/elements/table.rb +218 -0
  22. data/lib/firewatir/elements/table_cell.rb +54 -0
  23. data/lib/firewatir/elements/table_row.rb +100 -0
  24. data/lib/firewatir/elements/text_field.rb +218 -0
  25. data/lib/firewatir/exceptions.rb +10 -0
  26. data/lib/firewatir/firefox.rb +984 -0
  27. data/lib/firewatir/jssh_socket.rb +101 -0
  28. data/lib/firewatir/version.rb +5 -0
  29. data/lib/firewatir/winClicker.rb +122 -0
  30. data/lib/firewatir/x11.rb +192 -0
  31. data/unittests/attach_to_new_window_test.rb +49 -0
  32. data/unittests/bug_fixes_test.rb +195 -0
  33. data/unittests/buttons_xpath_test.rb +88 -0
  34. data/unittests/checkbox_test.rb +158 -0
  35. data/unittests/checkbox_xpath_test.rb +107 -0
  36. data/unittests/div_test.rb +275 -0
  37. data/unittests/ff_test.rb +47 -0
  38. data/unittests/filefield_test.rb +49 -0
  39. data/unittests/filefield_xpath_test.rb +35 -0
  40. data/unittests/form_test.rb +296 -0
  41. data/unittests/frame_test.rb +159 -0
  42. data/unittests/hidden_test.rb +85 -0
  43. data/unittests/hidden_xpath_test.rb +72 -0
  44. data/unittests/html/JavascriptClick.html +42 -0
  45. data/unittests/html/blankpage.html +12 -0
  46. data/unittests/html/buttons1.html +61 -0
  47. data/unittests/html/checkboxes1.html +71 -0
  48. data/unittests/html/complex_table.html +36 -0
  49. data/unittests/html/cssTest.html +42 -0
  50. data/unittests/html/div.html +72 -0
  51. data/unittests/html/div_xml.html +21 -0
  52. data/unittests/html/fileupload.html +45 -0
  53. data/unittests/html/formTest1.html +39 -0
  54. data/unittests/html/forms2.html +45 -0
  55. data/unittests/html/forms3.html +132 -0
  56. data/unittests/html/forms4.html +27 -0
  57. data/unittests/html/frame_buttons.html +4 -0
  58. data/unittests/html/frame_links.html +4 -0
  59. data/unittests/html/frame_multi.html +5 -0
  60. data/unittests/html/iframeTest.html +15 -0
  61. data/unittests/html/iframeTest1.html +14 -0
  62. data/unittests/html/iframeTest2.html +6 -0
  63. data/unittests/html/images/1.gif +0 -0
  64. data/unittests/html/images/2.GIF +0 -0
  65. data/unittests/html/images/3.GIF +0 -0
  66. data/unittests/html/images/button.jpg +0 -0
  67. data/unittests/html/images/circle.jpg +0 -0
  68. data/unittests/html/images/minus.GIF +0 -0
  69. data/unittests/html/images/originaltriangle.jpg +0 -0
  70. data/unittests/html/images/plus.gif +0 -0
  71. data/unittests/html/images/square.jpg +0 -0
  72. data/unittests/html/images/triangle.jpg +0 -0
  73. data/unittests/html/images1.html +67 -0
  74. data/unittests/html/javascriptevents.html +35 -0
  75. data/unittests/html/link_pass.html +11 -0
  76. data/unittests/html/links1.html +42 -0
  77. data/unittests/html/links2.html +11 -0
  78. data/unittests/html/modal_dialog.html +8 -0
  79. data/unittests/html/modal_dialog_launcher.html +12 -0
  80. data/unittests/html/nestedFrames.html +6 -0
  81. data/unittests/html/new_browser.html +18 -0
  82. data/unittests/html/new_browser_popup.html +8 -0
  83. data/unittests/html/pass.html +10 -0
  84. data/unittests/html/popups1.html +60 -0
  85. data/unittests/html/pre.html +28 -0
  86. data/unittests/html/radioButtons1.html +71 -0
  87. data/unittests/html/redirect.html +10 -0
  88. data/unittests/html/redirect1.html +9 -0
  89. data/unittests/html/redirect2.html +9 -0
  90. data/unittests/html/redirect3.html +9 -0
  91. data/unittests/html/select_tealeaf.html +54 -0
  92. data/unittests/html/selectboxes1.html +55 -0
  93. data/unittests/html/simple_table.html +26 -0
  94. data/unittests/html/simple_table_buttons.html +104 -0
  95. data/unittests/html/simple_table_columns.html +74 -0
  96. data/unittests/html/table1.html +165 -0
  97. data/unittests/html/tableCell_using_xpath.html +19 -0
  98. data/unittests/html/textarea.html +30 -0
  99. data/unittests/html/textfields1.html +62 -0
  100. data/unittests/html/textsearch.html +44 -0
  101. data/unittests/images_test.rb +198 -0
  102. data/unittests/images_xpath_test.rb +118 -0
  103. data/unittests/javascript_test.rb +75 -0
  104. data/unittests/links_test.rb +231 -0
  105. data/unittests/links_xpath_test.rb +79 -0
  106. data/unittests/mozilla_all_tests.rb +7 -0
  107. data/unittests/pre_test.rb +75 -0
  108. data/unittests/radios_test.rb +166 -0
  109. data/unittests/radios_xpath_test.rb +101 -0
  110. data/unittests/redirect_test.rb +41 -0
  111. data/unittests/selectbox_test.rb +142 -0
  112. data/unittests/selectbox_xpath_test.rb +129 -0
  113. data/unittests/setup.rb +29 -0
  114. data/unittests/table_test.rb +385 -0
  115. data/unittests/table_xpath_test.rb +185 -0
  116. data/unittests/textfields_test.rb +234 -0
  117. data/unittests/textfields_xpath_test.rb +113 -0
  118. metadata +208 -0
@@ -0,0 +1,100 @@
1
+ module FireWatir
2
+ #
3
+ # Description:
4
+ # Class for Table row element.
5
+ #
6
+ class TableRow < Element
7
+ attr_accessor :element_name
8
+
9
+ #
10
+ # Description:
11
+ # Locate the table row element on the page.
12
+ #
13
+ def locate
14
+ @o = nil
15
+ case @how
16
+ when :jssh_name
17
+ @element_name = @what
18
+ when :xpath
19
+ @element_name = element_by_xpath(@container, @what)
20
+ else
21
+ @element_name = locate_tagged_element("TR", @how, @what)
22
+ end
23
+ @o = self
24
+ end
25
+
26
+ #
27
+ # Description:
28
+ # Initializes the instance of table row object.
29
+ #
30
+ # Input:
31
+ # - how - Attribute to identify the table row element.
32
+ # - what - Value of that attribute.
33
+ #
34
+ def initialize(container, how, what)
35
+ @how = how
36
+ @what = what
37
+ @container = container
38
+ #super nil
39
+ end
40
+
41
+ #
42
+ # Description:
43
+ # Gets the length of columns in table row.
44
+ #
45
+ # Output:
46
+ # Length of columns in table row.
47
+ #
48
+ def column_count
49
+ assert_exists
50
+ arr_cells = cells
51
+ return arr_cells.length
52
+ end
53
+
54
+ #
55
+ # Description:
56
+ # Get cell at specified index in a row.
57
+ #
58
+ # Input:
59
+ # key - column index.
60
+ #
61
+ # Output:
62
+ # Table cell element at specified index.
63
+ #
64
+ def [] (key)
65
+ assert_exists
66
+ arr_cells = cells
67
+ return arr_cells[key - 1]
68
+ end
69
+
70
+ #
71
+ # Description:
72
+ # Iterate over each cell in a row.
73
+ #
74
+ def each
75
+ assert_exists
76
+ arr_cells = cells
77
+ for i in 0..arr_cells.length - 1 do
78
+ yield arr_cells[i]
79
+ end
80
+ end
81
+
82
+ #
83
+ # Description:
84
+ # Get array of all cells in Table Row
85
+ #
86
+ # Output:
87
+ # Array containing Table Cell elements.
88
+ #
89
+ def cells
90
+ assert_exists
91
+ arr_cells = get_cells
92
+ row_cells = Array.new(arr_cells.length)
93
+ for i in 0..arr_cells.length - 1 do
94
+ row_cells[i] = TableCell.new(@container, :jssh_name, arr_cells[i])
95
+ end
96
+ return row_cells
97
+ end
98
+
99
+ end # TableRow
100
+ end # FireWatir
@@ -0,0 +1,218 @@
1
+ module FireWatir
2
+ #
3
+ # Description:
4
+ # Class for Text Field element.
5
+ #
6
+ class TextField < InputElement
7
+ INPUT_TYPES = ["text", "password", "textarea"]
8
+
9
+ # Gets the size of the text field element.
10
+ def_wrap :size
11
+ # Gets max length of the text field element.
12
+ def_wrap :maxlength_string, :maxlength
13
+ def maxlength
14
+ maxlength_string.to_i
15
+ end
16
+ # Returns true if the text field is read only, false otherwise.
17
+ def_wrap :readonly?, :readOnly
18
+
19
+ #
20
+ # Description:
21
+ # Used to populate the properties in to_s method
22
+ #
23
+ #def text_string_creator
24
+ # n = []
25
+ # n << "length:".ljust(TO_S_SIZE) + self.size.to_s
26
+ # n << "max length:".ljust(TO_S_SIZE) + self.maxlength.to_s
27
+ # n << "read only:".ljust(TO_S_SIZE) + self.readonly?.to_s
28
+ #
29
+ # return n
30
+ #end
31
+ #private :text_string_creator
32
+
33
+ # TODO: Impelement the to_s method.
34
+ def to_s
35
+ assert_exists
36
+ super({"length" => "size","max length" => "maxlength","read only" => "readOnly" })
37
+ end
38
+
39
+ #
40
+ # Description:
41
+ # Checks if object is read-only or not.
42
+ #
43
+ def assert_not_readonly
44
+ raise ObjectReadOnlyException, "Textfield #{@how} and #{@what} is read only." if self.readonly?
45
+ end
46
+
47
+ #
48
+ # Description:
49
+ # Checks if the provided text matches with the contents of text field. Text can be a string or regular expression.
50
+ #
51
+ # Input:
52
+ # - containsThis - Text to verify.
53
+ #
54
+ # Output:
55
+ # True if provided text matches with the contents of text field, false otherwise.
56
+ #
57
+ def verify_contains( containsThis )
58
+ assert_exists
59
+ if containsThis.kind_of? String
60
+ return true if self.value == containsThis
61
+ elsif containsThis.kind_of? Regexp
62
+ return true if self.value.match(containsThis) != nil
63
+ end
64
+ return false
65
+ end
66
+
67
+ # this method is used to drag the entire contents of the text field to another text field
68
+ # 19 Jan 2005 - It is added as prototype functionality, and may change
69
+ # * destination_how - symbol, :id, :name how we identify the drop target
70
+ # * destination_what - string or regular expression, the name, id, etc of the text field that will be the drop target
71
+ # TODO: Can we have support for this in Firefox.
72
+ #def drag_contents_to( destination_how , destination_what)
73
+ # assert_exists
74
+ # destination = element.text_field(destination_how, destination_what)
75
+ # raise UnknownObjectException , "Unable to locate destination using #{destination_how } and #{destination_what } " if destination.exists? == false
76
+
77
+ # @o.focus
78
+ # @o.select()
79
+ # value = self.value
80
+
81
+ # @o.fireEvent("onSelect")
82
+ # @o.fireEvent("ondragstart")
83
+ # @o.fireEvent("ondrag")
84
+ # destination.fireEvent("onDragEnter")
85
+ # destination.fireEvent("onDragOver")
86
+ # destination.fireEvent("ondrop")
87
+
88
+ # @o.fireEvent("ondragend")
89
+ # destination.value= ( destination.value + value.to_s )
90
+ # self.value = ""
91
+ #end
92
+ # alias dragContentsTo drag_contents_to
93
+
94
+ #
95
+ # Description:
96
+ # Clears the contents of the text field.
97
+ # Raises ObjectDisabledException if text field is disabled.
98
+ # Raises ObjectReadOnlyException if text field is read only.
99
+ #
100
+ def clear
101
+ assert_exists
102
+ assert_enabled
103
+ assert_not_readonly
104
+
105
+ highlight(:set)
106
+
107
+ @o.scrollIntoView
108
+ @o.focus
109
+ @o.select()
110
+ @o.fireEvent("onSelect")
111
+ @o.value = ""
112
+ @o.fireEvent("onKeyPress")
113
+ @o.fireEvent("onChange")
114
+ @container.wait()
115
+ highlight(:clear)
116
+ end
117
+
118
+ #
119
+ # Description:
120
+ # Append the provided text to the contents of the text field.
121
+ # Raises ObjectDisabledException if text field is disabled.
122
+ # Raises ObjectReadOnlyException if text field is read only.
123
+ #
124
+ # Input:
125
+ # - setThis - Text to be appended.
126
+ #
127
+ def append( setThis)
128
+ assert_exists
129
+ assert_enabled
130
+ assert_not_readonly
131
+
132
+ highlight(:set)
133
+ @o.scrollIntoView
134
+ @o.focus
135
+ doKeyPress( setThis )
136
+ highlight(:clear)
137
+ end
138
+
139
+ #
140
+ # Description:
141
+ # Sets the contents of the text field to the provided text. Overwrite the existing contents.
142
+ # Raises ObjectDisabledException if text field is disabled.
143
+ # Raises ObjectReadOnlyException if text field is read only.
144
+ #
145
+ # Input:
146
+ # - setThis - Text to be set.
147
+ #
148
+ def set( setThis )
149
+ assert_exists
150
+ assert_enabled
151
+ assert_not_readonly
152
+
153
+ highlight(:set)
154
+ @o.scrollIntoView
155
+ @o.focus
156
+ @o.select()
157
+ @o.fireEvent("onSelect")
158
+ @o.value = ""
159
+ @o.fireEvent("onKeyPress")
160
+ doKeyPress( setThis )
161
+ highlight(:clear)
162
+ @o.fireEvent("onChange")
163
+ @o.fireEvent("onBlur")
164
+ end
165
+
166
+ #
167
+ # Description:
168
+ # Sets the text of the text field withoud firing the events like onKeyPress, onKeyDown etc. This should not be used generally, but it
169
+ # is useful in situations where you need to set large text to the text field and you know that you don't have any event to be
170
+ # fired.
171
+ #
172
+ # Input:
173
+ # - v - Text to be set.
174
+ #
175
+ #def value=(v)
176
+ # assert_exists
177
+ # @o.value = v.to_s
178
+ #end
179
+
180
+ #
181
+ # Description:
182
+ # Used to set the value of text box and fires the event onKeyPress, onKeyDown, onKeyUp after each character.
183
+ # Shouldnot be used externally. Used internally by set and append methods.
184
+ #
185
+ # Input:
186
+ # - value - The string to enter into the text field
187
+ #
188
+ def doKeyPress( value )
189
+ begin
190
+ max = maxlength
191
+ if (max > 0 && value.length > max)
192
+ original_value = value
193
+ value = original_value[0...max]
194
+ element.log " Supplied string is #{suppliedValue.length} chars, which exceeds the max length (#{max}) of the field. Using value: #{value}"
195
+ end
196
+ rescue
197
+ # probably a text area - so it doesnt have a max Length
198
+ end
199
+ for i in 0..value.length-1
200
+ #sleep element.typingspeed # typing speed
201
+ c = value[i,1]
202
+ #element.log " adding c.chr " + c #.chr.to_s
203
+ @o.value = "#{(@o.value.to_s + c)}" #c.chr
204
+ @o.fireEvent("onKeyDown")
205
+ @o.fireEvent("onKeyPress")
206
+ @o.fireEvent("onKeyUp")
207
+ end
208
+
209
+ end
210
+ private :doKeyPress
211
+
212
+ alias readOnly? :readonly?
213
+ alias getContents value
214
+ alias maxLength maxlength
215
+
216
+ end # TextField
217
+ end # FireWatir
218
+
@@ -0,0 +1,10 @@
1
+ require 'watir/exceptions' # from commonwatir
2
+
3
+ module Watir
4
+ module Exception
5
+ # This exception is thrown if we are unable to connect to JSSh.
6
+ class UnableToStartJSShException < WatirException; end
7
+ end
8
+ end
9
+
10
+
@@ -0,0 +1,984 @@
1
+
2
+ module FireWatir
3
+ include Watir::Exception
4
+
5
+ class Firefox
6
+ include FireWatir::Container
7
+
8
+ # XPath Result type. Return only first node that matches the xpath expression.
9
+ # More details: "http://developer.mozilla.org/en/docs/DOM:document.evaluate"
10
+ FIRST_ORDERED_NODE_TYPE = 9
11
+
12
+ # Description:
13
+ # Starts the firefox browser.
14
+ # On windows this starts the first version listed in the registry.
15
+ #
16
+ # Input:
17
+ # options - Hash of any of the following options:
18
+ # :waitTime - Time to wait for Firefox to start. By default it waits for 2 seconds.
19
+ # This is done because if Firefox is not started and we try to connect
20
+ # to jssh on port 9997 an exception is thrown.
21
+ # :profile - The Firefox profile to use. If none is specified, Firefox will use
22
+ # the last used profile.
23
+ # :suppress_launch_process - do not create a new firefox process. Connect to an existing one.
24
+
25
+ # TODO: Start the firefox version given by user.
26
+
27
+ def initialize(options = {})
28
+ if(options.kind_of?(Integer))
29
+ options = {:waitTime => options}
30
+ end
31
+
32
+ # check for jssh not running, firefox may be open but not with -jssh
33
+ # if its not open at all, regardless of the :suppress_launch_process option start it
34
+ # error if running without jssh, we don't want to kill their current window (mac only)
35
+ jssh_down = false
36
+ begin
37
+ set_defaults()
38
+ rescue Watir::Exception::UnableToStartJSShException
39
+ jssh_down = true
40
+ end
41
+
42
+ if current_os == :macosx && !%x{ps x | grep firefox-bin | grep -v grep}.empty?
43
+ raise "Firefox is running without -jssh" if jssh_down
44
+ open_window unless options[:suppress_launch_process]
45
+ elsif not options[:suppress_launch_process]
46
+ launch_browser(options)
47
+ end
48
+
49
+ set_defaults()
50
+ get_window_number()
51
+ set_browser_document()
52
+ end
53
+
54
+ def inspect
55
+ '#<%s:0x%x url=%s title=%s>' % [self.class, hash*2, url.inspect, title.inspect]
56
+ end
57
+
58
+
59
+ # Launches firebox browser
60
+ # options as .new
61
+
62
+ def launch_browser(options = {})
63
+
64
+ if(options[:profile])
65
+ profile_opt = "-no-remote -P #{options[:profile]}"
66
+ else
67
+ profile_opt = ""
68
+ end
69
+
70
+ bin = path_to_bin()
71
+ @t = Thread.new { system("#{bin} -jssh #{profile_opt}") }
72
+ sleep options[:waitTime] || 2
73
+
74
+ end
75
+ private :launch_browser
76
+
77
+ # Creates a new instance of Firefox. Loads the URL and return the instance.
78
+ # Input:
79
+ # url - url of the page to be loaded.
80
+ def self.start(url)
81
+ ff = Firefox.new
82
+ ff.goto(url)
83
+ return ff
84
+ end
85
+
86
+ # Gets the window number opened.
87
+ # Currently, this returns the most recently opened window, which may or may
88
+ # not be the current window.
89
+ def get_window_number()
90
+ # If at any time a non-browser window like the "Downloads" window
91
+ # pops up, it will become the topmost window, so make sure we
92
+ # ignore it.
93
+ window_count = js_eval("getWindows().length").to_i - 1
94
+ while js_eval("getWindows()[#{window_count}].getBrowser") == ''
95
+ window_count -= 1;
96
+ end
97
+
98
+ # now correctly handles instances where only browserless windows are open
99
+ # opens one we can use if count is 0
100
+
101
+ if window_count < 0
102
+ open_window
103
+ window_count = 1
104
+ end
105
+ @window_index = window_count
106
+ end
107
+ private :get_window_number
108
+
109
+ # Loads the given url in the browser. Waits for the page to get loaded.
110
+ def goto(url)
111
+ get_window_number()
112
+ set_browser_document()
113
+ js_eval "#{browser_var}.loadURI(\"#{url}\")"
114
+ wait()
115
+ end
116
+
117
+ # Loads the previous page (if there is any) in the browser. Waits for the page to get loaded.
118
+ def back()
119
+ js_eval "if(#{browser_var}.canGoBack) #{browser_var}.goBack()"
120
+ wait()
121
+ end
122
+
123
+ # Loads the next page (if there is any) in the browser. Waits for the page to get loaded.
124
+ def forward()
125
+ js_eval "if(#{browser_var}.canGoForward) #{browser_var}.goForward()"
126
+ wait()
127
+ end
128
+
129
+ # Reloads the current page in the browser. Waits for the page to get loaded.
130
+ def refresh()
131
+ js_eval "#{browser_var}.reload()"
132
+ wait()
133
+ end
134
+
135
+ # Executes the given JavaScript string
136
+ def execute_script(source)
137
+ result = js_eval source.to_s
138
+ wait()
139
+
140
+ result
141
+ end
142
+
143
+ private
144
+ # This function creates a new socket at port 9997 and sets the default values for instance and class variables.
145
+ # Generatesi UnableToStartJSShException if cannot connect to jssh even after 3 tries.
146
+ def set_defaults(no_of_tries = 0)
147
+ # JSSH listens on port 9997. Create a new socket to connect to port 9997.
148
+ begin
149
+ $jssh_socket = TCPSocket::new(MACHINE_IP, "9997")
150
+ $jssh_socket.sync = true
151
+ read_socket()
152
+ rescue
153
+ no_of_tries += 1
154
+ retry if no_of_tries < 3
155
+ 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"
156
+ end
157
+ @error_checkers = []
158
+ end
159
+
160
+ # Sets the document, window and browser variables to point to correct object in JSSh.
161
+ def set_browser_document
162
+ # Add eventlistener for browser window so that we can reset the document back whenever there is redirect
163
+ # or browser loads on its own after some time. Useful when you are searching for flight results etc and
164
+ # page goes to search page after that it goes automatically to results page.
165
+ # Details : http://zenit.senecac.on.ca/wiki/index.php/Mozilla.dev.tech.xul#What_is_an_example_of_addProgressListener.3F
166
+ jssh_command = "var listObj = new Object();"; # create new object
167
+ jssh_command << "listObj.wpl = Components.interfaces.nsIWebProgressListener;"; # set the web progress listener.
168
+ jssh_command << "listObj.QueryInterface = function(aIID) {
169
+ if (aIID.equals(listObj.wpl) ||
170
+ aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
171
+ aIID.equals(Components.interfaces.nsISupports))
172
+ return this;
173
+ throw Components.results.NS_NOINTERFACE;
174
+ };" # set function to locate the object via QueryInterface
175
+ jssh_command << "listObj.onStateChange = function(aProgress, aRequest, aFlag, aStatus) {
176
+ if (aFlag & listObj.wpl.STATE_STOP) {
177
+ if ( aFlag & listObj.wpl.STATE_IS_NETWORK ) {
178
+ #{document_var} = #{browser_var}.contentDocument;
179
+ #{body_var} = #{document_var}.body;
180
+ }
181
+ }
182
+ };" # add function to be called when window state is change. When state is STATE_STOP &
183
+ # STATE_IS_NETWORK then only everything is loaded. Now we can reset our variables.
184
+ jssh_command.gsub!(/\n/, "")
185
+ js_eval jssh_command
186
+
187
+ jssh_command = "var #{window_var} = getWindows()[#{@window_index}];"
188
+ jssh_command << "var #{browser_var} = #{window_var}.getBrowser();"
189
+ # Add listener create above to browser object
190
+ jssh_command << "#{browser_var}.addProgressListener( listObj,Components.interfaces.nsIWebProgress.NOTIFY_STATE_WINDOW );"
191
+ jssh_command << "var #{document_var} = #{browser_var}.contentDocument;"
192
+ jssh_command << "var #{body_var} = #{document_var}.body;"
193
+ js_eval jssh_command
194
+
195
+ @window_title = js_eval "#{document_var}.title"
196
+ @window_url = js_eval "#{document_var}.URL"
197
+ end
198
+
199
+ public
200
+ def window_var
201
+ "window"
202
+ end
203
+ #private
204
+ def browser_var
205
+ "browser"
206
+ end
207
+ def document_var # unfinished
208
+ "document"
209
+ end
210
+ def body_var # unfinished
211
+ "body"
212
+ end
213
+
214
+ public
215
+ # Closes the window.
216
+ def close
217
+
218
+ if js_eval("getWindows().length").to_i == 1
219
+ js_eval("getWindows()[0].close()")
220
+
221
+ if current_os == :macosx
222
+ %x{ osascript -e 'tell application "Firefox" to quit' }
223
+ end
224
+
225
+ # wait for the app to close properly
226
+ @t.join if @t
227
+ else
228
+ # Check if window exists, because there may be the case that it has been closed by click event on some element.
229
+ # For e.g: Close Button, Close this Window link etc.
230
+ window_number = find_window(:url, @window_url)
231
+
232
+ # If matching window found. Close the window.
233
+ if window_number > 0
234
+ js_eval "getWindows()[#{window_number}].close()"
235
+ end
236
+
237
+ end
238
+ end
239
+
240
+ # Closes all firefox windows
241
+ def close_all
242
+ total_windows = js_eval("getWindows().length").to_i
243
+
244
+ # start from last window
245
+ while(total_windows > 0) do
246
+ js_eval "getWindows()[#{total_windows - 1}].close()"
247
+ total_windows = total_windows - 1
248
+ end
249
+
250
+ if current_os == :macosx
251
+ %x{ osascript -e 'tell application "Firefox" to quit' }
252
+ end
253
+
254
+ if current_os == :windows
255
+ system("taskkill /im firefox.exe /f /t >nul 2>&1")
256
+ end
257
+ end
258
+
259
+ # Used for attaching pop up window to an existing Firefox window, either by url or title.
260
+ # ff.attach(:url, 'http://www.google.com')
261
+ # ff.attach(:title, 'Google')
262
+ #
263
+ # Output:
264
+ # Instance of newly attached window.
265
+ def attach(how, what)
266
+
267
+ $stderr.puts("warning: #{self.class}.attach is experimental") if $VERBOSE
268
+ window_number = find_window(how, what)
269
+
270
+ if(window_number.nil?)
271
+ raise NoMatchingWindowFoundException.new("Unable to locate window, using #{how} and #{what}")
272
+ elsif(window_number >= 0)
273
+ @window_index = window_number
274
+ set_browser_document()
275
+ end
276
+ self
277
+ end
278
+
279
+ # Class method to return a browser object if a window matches for how
280
+ # and what. Window can be referenced by url or title.
281
+ # The second argument can be either a string or a regular expression.
282
+ # Watir::Browser.attach(:url, 'http://www.google.com')
283
+ # Watir::Browser.attach(:title, 'Google')
284
+ def self.attach how, what
285
+ br = new :suppress_launch_process => true # don't create window
286
+ br.attach(how, what)
287
+ br
288
+ end
289
+
290
+ # loads up a new window in an existing process
291
+ # Watir::Browser.attach() with no arguments passed the attach method will create a new window
292
+ # this will only be called one time per instance we're only ever going to run in 1 window
293
+
294
+ def open_window
295
+
296
+ if @opened_new_window
297
+ return @opened_new_window
298
+ end
299
+
300
+ jssh_command = "var windows = getWindows(); var window = windows[0];
301
+ window.open();
302
+ var windows = getWindows(); var window_number = windows.length - 1;
303
+ window_number;"
304
+
305
+ window_number = js_eval(jssh_command).to_i
306
+ @opened_new_window = window_number
307
+ return window_number if window_number >= 0
308
+ end
309
+ private :open_window
310
+
311
+ # return the window index for the browser window with the given title or url.
312
+ # how - :url or :title
313
+ # what - string or regexp
314
+ # Start searching windows in reverse order so that we attach/find the latest opened window.
315
+ def find_window(how, what)
316
+ jssh_command = "var windows = getWindows(); var window_number = false; var found = false;
317
+ for(var i = windows.length - 1; i >= 0; i--)
318
+ {
319
+ var attribute = '';
320
+ if(typeof(windows[i].getBrowser) != 'function')
321
+ {
322
+ continue;
323
+ }
324
+ var browser = windows[i].getBrowser();
325
+ if(!browser)
326
+ {
327
+ continue;
328
+ }
329
+ if(\"#{how}\" == \"url\")
330
+ {
331
+ attribute = browser.contentDocument.URL;
332
+ }
333
+ if(\"#{how}\" == \"title\")
334
+ {
335
+ attribute = browser.contentDocument.title;
336
+ }"
337
+ if(what.class == Regexp)
338
+ jssh_command << "var regExp = new RegExp(#{what.inspect});
339
+ found = regExp.test(attribute);"
340
+ else
341
+ jssh_command << "found = (attribute == \"#{what}\");"
342
+ end
343
+
344
+ jssh_command << "if(found)
345
+ {
346
+ window_number = i;
347
+ break;
348
+ }
349
+ }
350
+ window_number;"
351
+ window_number = js_eval(jssh_command).to_s
352
+ return window_number == 'false' ? nil : window_number.to_i
353
+ end
354
+ private :find_window
355
+
356
+ #
357
+ # Description:
358
+ # Matches the given text with the current text shown in the browser.
359
+ #
360
+ # Input:
361
+ # target - Text to match. Can be a string or regex
362
+ #
363
+ # Output:
364
+ # Returns the index if the specified text was found.
365
+ # Returns matchdata object if the specified regexp was found.
366
+ #
367
+ def contains_text(target)
368
+ #puts "Text to match is : #{match_text}"
369
+ #puts "Html is : #{self.text}"
370
+ case target
371
+ when Regexp
372
+ self.text.match(target)
373
+ when String
374
+ self.text.index(target)
375
+ else
376
+ raise TypeError, "Argument #{target} should be a string or regexp."
377
+ end
378
+ end
379
+
380
+ # Returns the url of the page currently loaded in the browser.
381
+ def url
382
+ @window_url = js_eval "#{document_var}.URL"
383
+ end
384
+
385
+ # Returns the title of the page currently loaded in the browser.
386
+ def title
387
+ @window_title = js_eval "#{document_var}.title"
388
+ end
389
+
390
+ # Returns the Status of the page currently loaded in the browser from statusbar.
391
+ #
392
+ # Output:
393
+ # Status of the page.
394
+ #
395
+ def status
396
+ js_status = js_eval("#{window_var}.status")
397
+ js_status.empty? ? js_eval("#{window_var}.XULBrowserWindow.statusText;") : js_status
398
+ end
399
+
400
+
401
+ # Returns the html of the page currently loaded in the browser.
402
+ def html
403
+ result = js_eval("var htmlelem = #{document_var}.getElementsByTagName('html')[0]; htmlelem.innerHTML")
404
+ return "<html>" + result + "</html>"
405
+ end
406
+
407
+ # Returns the text of the page currently loaded in the browser.
408
+ def text
409
+ js_eval("#{body_var}.textContent").strip
410
+ end
411
+
412
+ # Maximize the current browser window.
413
+ def maximize()
414
+ js_eval "#{window_var}.maximize()"
415
+ end
416
+
417
+ # Minimize the current browser window.
418
+ def minimize()
419
+ js_eval "#{window_var}.minimize()"
420
+ end
421
+
422
+ # Waits for the page to get loaded.
423
+ def wait(last_url = nil)
424
+ #puts "In wait function "
425
+ isLoadingDocument = ""
426
+ start = Time.now
427
+
428
+ while isLoadingDocument != "false"
429
+ isLoadingDocument = js_eval("#{browser_var}=#{window_var}.getBrowser(); #{browser_var}.webProgress.isLoadingDocument;")
430
+ #puts "Is browser still loading page: #{isLoadingDocument}"
431
+
432
+ # Raise an exception if the page fails to load
433
+ if (Time.now - start) > 300
434
+ raise "Page Load Timeout"
435
+ end
436
+ end
437
+ # If the redirect is to a download attachment that does not reload this page, this
438
+ # method will loop forever. Therefore, we need to ensure that if this method is called
439
+ # twice with the same URL, we simply accept that we're done.
440
+ url = js_eval("#{browser_var}.contentDocument.URL")
441
+
442
+ if(url != last_url)
443
+ # Check for Javascript redirect. As we are connected to Firefox via JSSh. JSSh
444
+ # doesn't detect any javascript redirects so check it here.
445
+ # If page redirects to itself that this code will enter in infinite loop.
446
+ # So we currently don't wait for such a page.
447
+ # wait variable in JSSh tells if we should wait more for the page to get loaded
448
+ # or continue. -1 means page is not redirected. Anyother positive values means wait.
449
+ jssh_command = "var wait = -1; var meta = null; meta = #{browser_var}.contentDocument.getElementsByTagName('meta');
450
+ if(meta != null)
451
+ {
452
+ var doc_url = #{browser_var}.contentDocument.URL;
453
+ for(var i=0; i< meta.length;++i)
454
+ {
455
+ var content = meta[i].content;
456
+ var regex = new RegExp(\"^refresh$\", \"i\");
457
+ if(regex.test(meta[i].httpEquiv))
458
+ {
459
+ var arrContent = content.split(';');
460
+ var redirect_url = null;
461
+ if(arrContent.length > 0)
462
+ {
463
+ if(arrContent.length > 1)
464
+ redirect_url = arrContent[1];
465
+
466
+ if(redirect_url != null)
467
+ {
468
+ regex = new RegExp(\"^.*\" + redirect_url + \"$\");
469
+ if(!regex.test(doc_url))
470
+ {
471
+ wait = arrContent[0];
472
+ }
473
+ }
474
+ break;
475
+ }
476
+ }
477
+ }
478
+ }
479
+ wait;"
480
+ wait_time = js_eval(jssh_command).to_i
481
+ begin
482
+ if(wait_time != -1)
483
+ sleep(wait_time)
484
+ # Call wait again. In case there are multiple redirects.
485
+ js_eval "#{browser_var} = #{window_var}.getBrowser()"
486
+ wait(url)
487
+ end
488
+ rescue
489
+ end
490
+ end
491
+ set_browser_document()
492
+ run_error_checks()
493
+ return self
494
+ end
495
+
496
+ # Add an error checker that gets called on every page load.
497
+ # * checker - a Proc object
498
+ def add_checker(checker)
499
+ @error_checkers << checker
500
+ end
501
+
502
+ # Disable an error checker
503
+ # * checker - a Proc object that is to be disabled
504
+ def disable_checker(checker)
505
+ @error_checkers.delete(checker)
506
+ end
507
+
508
+ # Run the predefined error checks. This is automatically called on every page load.
509
+ def run_error_checks
510
+ @error_checkers.each { |e| e.call(self) }
511
+ end
512
+
513
+
514
+ #def jspopup_appeared(popupText = "", wait = 2)
515
+ # winHelper = WindowHelper.new()
516
+ # return winHelper.hasPopupAppeared(popupText, wait)
517
+ #end
518
+
519
+ #
520
+ # Description:
521
+ # Redefines the alert and confirm methods on the basis of button to be clicked.
522
+ # This is done so that JSSh doesn't get blocked. You should use click_no_wait method before calling this function.
523
+ #
524
+ # Typical Usage:
525
+ # ff.button(:id, "button").click_no_wait
526
+ # ff.click_jspopup_button("OK")
527
+ #
528
+ # Input:
529
+ # button - JavaScript button to be clicked. Values can be OK or Cancel
530
+ #
531
+ #def click_jspopup_button(button)
532
+ # button = button.downcase
533
+ # element = Element.new(nil)
534
+ # element.click_js_popup(button)
535
+ #end
536
+
537
+ #
538
+ # Description:
539
+ # Tells FireWatir to click javascript button in case one comes after performing some action on an element. Matches
540
+ # text of pop up with one if supplied as parameter. If text matches clicks the button else stop script execution until
541
+ # pop up is dismissed by manual intervention.
542
+ #
543
+ # Input:
544
+ # button - JavaScript button to be clicked. Values can be OK or Cancel
545
+ # waitTime - Time to wait for pop up to come. Not used just for compatibility with Watir.
546
+ # userInput - Not used just for compatibility with Watir
547
+ # text - Text that should appear on pop up.
548
+ #
549
+ def startClicker(button, waitTime = 1, userInput = nil, text = nil)
550
+ jssh_command = "var win = #{browser_var}.contentWindow;"
551
+ if(button =~ /ok/i)
552
+ jssh_command << "var popuptext = '';
553
+ var old_alert = win.alert;
554
+ var old_confirm = win.confirm;
555
+ win.alert = function(param) {"
556
+ if(text != nil)
557
+ jssh_command << "if(param == \"#{text}\") {
558
+ popuptext = param;
559
+ return true;
560
+ }
561
+ else {
562
+ popuptext = param;
563
+ win.alert = old_alert;
564
+ win.alert(param);
565
+ }"
566
+ else
567
+ jssh_command << "popuptext = param; return true;"
568
+ end
569
+ jssh_command << "};
570
+ win.confirm = function(param) {"
571
+ if(text != nil)
572
+ jssh_command << "if(param == \"#{text}\") {
573
+ popuptext = param;
574
+ return true;
575
+ }
576
+ else {
577
+ win.confirm = old_confirm;
578
+ win.confirm(param);
579
+ }"
580
+ else
581
+ jssh_command << "popuptext = param; return true;"
582
+ end
583
+ jssh_command << "};"
584
+
585
+ elsif(button =~ /cancel/i)
586
+ jssh_command = "var old_confirm = win.confirm;
587
+ win.confirm = function(param) {"
588
+ if(text != nil)
589
+ jssh_command << "if(param == \"#{text}\") {
590
+ popuptext = param;
591
+ return false;
592
+ }
593
+ else {
594
+ win.confirm = old_confirm;
595
+ win.confirm(param);
596
+ }"
597
+ else
598
+ jssh_command << "popuptext = param; return false;"
599
+ end
600
+ jssh_command << "};"
601
+ end
602
+ js_eval jssh_command
603
+ end
604
+
605
+ #
606
+ # Description:
607
+ # Returns text of javascript pop up in case it comes.
608
+ #
609
+ # Output:
610
+ # Text shown in javascript pop up.
611
+ #
612
+ def get_popup_text()
613
+ return_value = js_eval "popuptext"
614
+ # reset the variable
615
+ js_eval "popuptext = ''"
616
+ return return_value
617
+ end
618
+
619
+ # Returns the document element of the page currently loaded in the browser.
620
+ def document
621
+ Document.new(self)
622
+ end
623
+
624
+ # Returns the first element that matches the given xpath expression or query.
625
+ def element_by_xpath(xpath)
626
+ temp = Element.new(nil, self)
627
+ element_name = temp.element_by_xpath(self, xpath)
628
+ return element_factory(element_name)
629
+ end
630
+
631
+ # Return object of correct Element class while using XPath to get the element.
632
+ def element_factory(element_name)
633
+ jssh_type = Element.new(element_name,self).element_type
634
+ #puts "jssh type is : #{jssh_type}" # DEBUG
635
+ candidate_class = jssh_type =~ /HTML(.*)Element/ ? $1 : ''
636
+ #puts candidate_class # DEBUG
637
+ if candidate_class == 'Input'
638
+ input_type = js_eval("#{element_name}.type").downcase.strip
639
+ firewatir_class = input_class(input_type)
640
+ else
641
+ firewatir_class = jssh2firewatir(candidate_class)
642
+ end
643
+
644
+ #puts firewatir_class # DEBUG
645
+ klass = FireWatir.const_get(firewatir_class)
646
+
647
+ if klass == Element
648
+ klass.new(element_name,self)
649
+ elsif klass == CheckBox
650
+ klass.new(self,:jssh_name,element_name,["checkbox"])
651
+ elsif klass == Radio
652
+ klass.new(self,:jssh_name,element_name,["radio"])
653
+ else
654
+ klass.new(self,:jssh_name,element_name)
655
+ end
656
+ end
657
+ private :element_factory
658
+
659
+ # Return the class name for element of input type depending upon its type like checkbox, radio etc.
660
+ def input_class(input_type)
661
+ hash = {
662
+ 'select-one' => 'SelectList',
663
+ 'select-multiple' => 'SelectList',
664
+ 'text' => 'TextField',
665
+ 'password' => 'TextField',
666
+ 'textarea' => 'TextField',
667
+ # TODO when there's no type, it's a TextField
668
+ 'file' => 'FileField',
669
+ 'checkbox' => 'CheckBox',
670
+ 'radio' => 'Radio',
671
+ 'reset' => 'Button',
672
+ 'button' => 'Button',
673
+ 'submit' => 'Button',
674
+ 'image' => 'Button'
675
+ }
676
+ hash.default = 'Element'
677
+
678
+ hash[input_type]
679
+ end
680
+ private :input_class
681
+
682
+ # For a provided element type returned by JSSh like HTMLDivElement,
683
+ # returns its corresponding class in Firewatir.
684
+ def jssh2firewatir(candidate_class)
685
+ hash = {
686
+ 'Div' => 'Div',
687
+ 'Button' => 'Button',
688
+ 'Frame' => 'Frame',
689
+ 'Span' => 'Span',
690
+ 'Paragraph' => 'P',
691
+ 'Label' => 'Label',
692
+ 'Form' => 'Form',
693
+ 'Image' => 'Image',
694
+ 'Table' => 'Table',
695
+ 'TableCell' => 'TableCell',
696
+ 'TableRow' => 'TableRow',
697
+ 'Select' => 'SelectList',
698
+ 'Link' => 'Link',
699
+ 'Anchor' => 'Link' # FIXME is this right?
700
+ #'Option' => 'Option' #Option uses a different constructor
701
+ }
702
+ hash.default = 'Element'
703
+ hash[candidate_class]
704
+ end
705
+ private :jssh2firewatir
706
+
707
+ #
708
+ # Description:
709
+ # Returns the array of elements that matches the xpath query.
710
+ #
711
+ # Input:
712
+ # Xpath expression or query.
713
+ #
714
+ # Output:
715
+ # Array of elements matching xpath query.
716
+ #
717
+ def elements_by_xpath(xpath)
718
+ element = Element.new(nil, self)
719
+ elem_names = element.elements_by_xpath(self, xpath)
720
+ elem_names.inject([]) {|elements,name| elements << element_factory(name)}
721
+ end
722
+
723
+ #
724
+ # Description:
725
+ # Show all the forms available on the page.
726
+ #
727
+ # Output:
728
+ # Name, id, method and action of all the forms available on the page.
729
+ #
730
+ def show_forms
731
+ forms = Document.new(self).get_forms()
732
+ count = forms.length
733
+ puts "There are #{count} forms"
734
+ for i in 0..count - 1 do
735
+ puts "Form name: " + forms[i].name
736
+ puts " id: " + forms[i].id
737
+ puts " method: " + forms[i].attribute_value("method")
738
+ puts " action: " + forms[i].action
739
+ end
740
+ end
741
+ alias showForms show_forms
742
+
743
+ #
744
+ # Description:
745
+ # Show all the images available on the page.
746
+ #
747
+ # Output:
748
+ # Name, id, src and index of all the images available on the page.
749
+ #
750
+ def show_images
751
+ images = Document.new(self).get_images
752
+ puts "There are #{images.length} images"
753
+ index = 1
754
+ images.each do |l|
755
+ puts "image: name: #{l.name}"
756
+ puts " id: #{l.id}"
757
+ puts " src: #{l.src}"
758
+ puts " index: #{index}"
759
+ index += 1
760
+ end
761
+ end
762
+ alias showImages show_images
763
+
764
+ #
765
+ # Description:
766
+ # Show all the links available on the page.
767
+ #
768
+ # Output:
769
+ # Name, id, href and index of all the links available on the page.
770
+ #
771
+ def show_links
772
+ links = Document.new(self).get_links
773
+ puts "There are #{links.length} links"
774
+ index = 1
775
+ links.each do |l|
776
+ puts "link: name: #{l.name}"
777
+ puts " id: #{l.id}"
778
+ puts " href: #{l.href}"
779
+ puts " index: #{index}"
780
+ index += 1
781
+ end
782
+ end
783
+ alias showLinks show_links
784
+
785
+ #
786
+ # Description:
787
+ # Show all the divs available on the page.
788
+ #
789
+ # Output:
790
+ # Name, id, class and index of all the divs available on the page.
791
+ #
792
+ def show_divs
793
+ divs = Document.new(self).get_divs
794
+ puts "There are #{divs.length} divs"
795
+ index = 1
796
+ divs.each do |l|
797
+ puts "div: name: #{l.name}"
798
+ puts " id: #{l.id}"
799
+ puts " class: #{l.className}"
800
+ puts " index: #{index}"
801
+ index += 1
802
+ end
803
+ end
804
+ alias showDivs show_divs
805
+
806
+ #
807
+ # Description:
808
+ # Show all the tables available on the page.
809
+ #
810
+ # Output:
811
+ # Id, row count, column count (only first row) and index of all the tables available on the page.
812
+ #
813
+ def show_tables
814
+ tables = Document.new(self).get_tables
815
+ puts "There are #{tables.length} tables"
816
+ index = 1
817
+ tables.each do |l|
818
+ puts "table: id: #{l.id}"
819
+ puts " rows: #{l.row_count}"
820
+ puts " columns: #{l.column_count}"
821
+ puts " index: #{index}"
822
+ index += 1
823
+ end
824
+ end
825
+ alias showTables show_tables
826
+
827
+ #
828
+ # Description:
829
+ # Show all the pre elements available on the page.
830
+ #
831
+ # Output:
832
+ # Id, name and index of all the pre elements available on the page.
833
+ #
834
+ def show_pres
835
+ pres = Document.new(self).get_pres
836
+ puts "There are #{pres.length} pres"
837
+ index = 1
838
+ pres.each do |l|
839
+ puts "pre: id: #{l.id}"
840
+ puts " name: #{l.name}"
841
+ puts " index: #{index}"
842
+ index += 1
843
+ end
844
+ end
845
+ alias showPres show_pres
846
+
847
+ #
848
+ # Description:
849
+ # Show all the spans available on the page.
850
+ #
851
+ # Output:
852
+ # Name, id, class and index of all the spans available on the page.
853
+ #
854
+ def show_spans
855
+ spans = Document.new(self).get_spans
856
+ puts "There are #{spans.length} spans"
857
+ index = 1
858
+ spans.each do |l|
859
+ puts "span: name: #{l.name}"
860
+ puts " id: #{l.id}"
861
+ puts " class: #{l.className}"
862
+ puts " index: #{index}"
863
+ index += 1
864
+ end
865
+ end
866
+ alias showSpans show_spans
867
+
868
+ #
869
+ # Description:
870
+ # Show all the labels available on the page.
871
+ #
872
+ # Output:
873
+ # Name, id, for and index of all the labels available on the page.
874
+ #
875
+ def show_labels
876
+ labels = Document.new(self).get_labels
877
+ puts "There are #{labels.length} labels"
878
+ index = 1
879
+ labels.each do |l|
880
+ puts "label: name: #{l.name}"
881
+ puts " id: #{l.id}"
882
+ puts " for: #{l.for}"
883
+ puts " index: #{index}"
884
+ index += 1
885
+ end
886
+ end
887
+ alias showLabels show_labels
888
+
889
+ #
890
+ # Description:
891
+ # Show all the frames available on the page. Doesn't show nested frames.
892
+ #
893
+ # Output:
894
+ # Name, and index of all the frames available on the page.
895
+ #
896
+ def show_frames
897
+ jssh_command = "var frameset = #{window_var}.frames;
898
+ var elements_frames = new Array();
899
+ for(var i = 0; i < frameset.length; i++)
900
+ {
901
+ var frames = frameset[i].frames;
902
+ for(var j = 0; j < frames.length; j++)
903
+ {
904
+ elements_frames.push(frames[j].frameElement);
905
+ }
906
+ }
907
+ elements_frames.length;"
908
+
909
+ length = js_eval(jssh_command).to_i
910
+
911
+ puts "There are #{length} frames"
912
+
913
+ frames = Array.new(length)
914
+ for i in 0..length - 1 do
915
+ frames[i] = Frame.new(self, :jssh_name, "elements_frames[#{i}]")
916
+ end
917
+
918
+ for i in 0..length - 1 do
919
+ puts "frame: name: #{frames[i].name}"
920
+ puts " index: #{i+1}"
921
+ end
922
+ end
923
+ alias showFrames show_frames
924
+
925
+ private
926
+
927
+ def path_to_bin
928
+ path = case current_os()
929
+ when :windows
930
+ path_from_registry
931
+ when :macosx
932
+ path_from_spotlight
933
+ when :linux
934
+ `which firefox`.strip
935
+ end
936
+
937
+ raise "unable to locate Firefox executable" if path.nil? || path.empty?
938
+
939
+ path
940
+ end
941
+
942
+ def current_os
943
+ return @current_os if defined?(@current_os)
944
+
945
+ platform = RUBY_PLATFORM =~ /java/ ? Java::java.lang.System.getProperty("os.name") : RUBY_PLATFORM
946
+
947
+ @current_os = case platform
948
+ when /mingw32|mswin|windows/i
949
+ :windows
950
+ when /darwin|mac os/i
951
+ :macosx
952
+ when /linux/i
953
+ :linux
954
+ end
955
+ end
956
+
957
+ def path_from_registry
958
+ require 'win32/registry.rb'
959
+ lm = Win32::Registry::HKEY_LOCAL_MACHINE
960
+ lm.open('SOFTWARE\Mozilla\Mozilla Firefox') do |reg|
961
+ reg1 = lm.open("SOFTWARE\\Mozilla\\Mozilla Firefox\\#{reg.keys[0]}\\Main")
962
+ if entry = reg1.find { |key, type, data| key =~ /pathtoexe/i }
963
+ return entry.last
964
+ end
965
+ end
966
+ rescue LoadError
967
+ if RUBY_PLATFORM =~ /java/
968
+ return(ENV['FIREFOX_HOME'] or raise(
969
+ NotImplementedError,
970
+ 'No Registry support in this JRuby; upgrade or set FIREFOX_HOME'))
971
+ else
972
+ raise
973
+ end
974
+ end
975
+
976
+ def path_from_spotlight
977
+ ff = %x[mdfind 'kMDItemCFBundleIdentifier == "org.mozilla.firefox"']
978
+ ff = ff.empty? ? '/Applications/Firefox.app' : ff.split("\n").first
979
+
980
+ "#{ff}/Contents/MacOS/firefox-bin"
981
+ end
982
+
983
+ end # Firefox
984
+ end # FireWatir