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,101 @@
1
+ module JsshSocket
2
+ # Evaluate javascript and return result. Raise an exception if an error occurred.
3
+ def js_eval(str)
4
+ str.gsub!("\n", "")
5
+ jssh_socket.send("#{str};\n", 0)
6
+ value = read_socket()
7
+ if md = /^(\w+)Error:(.*)$/.match(value)
8
+ errclassname="JS#{md[1]}Error"
9
+ unless JsshSocket.const_defined?(errclassname)
10
+ JsshSocket.const_set(errclassname, Class.new(StandardError))
11
+ end
12
+ raise JsshSocket.const_get(errclassname), md[2]
13
+ end
14
+ value
15
+ end
16
+
17
+ # evaluate the provides javascript method on the current object and return
18
+ # the result
19
+ def js_eval_method method_name
20
+ js_eval("#{element_object}.#{method_name}")
21
+ end
22
+
23
+ def jssh_socket
24
+ $jssh_socket || @container.jssh_socket
25
+ end
26
+
27
+ #
28
+ # Description:
29
+ # Reads the javascript execution result from the jssh socket.
30
+ #
31
+ # Input:
32
+ # - socket - It is the jssh socket, the only point of communication between the browser and firewatir scripts.
33
+ #
34
+ # Output:
35
+ # The javascript execution result as string.
36
+ #
37
+ def read_socket(socket = jssh_socket)
38
+ return_value = ""
39
+ data = ""
40
+ receive = true
41
+ #puts Thread.list
42
+ s = nil
43
+ while(s == nil) do
44
+ s = Kernel.select([socket] , nil , nil, 1)
45
+ end
46
+ #if(s != nil)
47
+ for stream in s[0]
48
+ data = stream.recv(1024)
49
+ #puts "data is : #{data}"
50
+ while(receive)
51
+ #while(data.length == 1024)
52
+ return_value += data
53
+ if(return_value.include?("\n> "))
54
+ receive = false
55
+ else
56
+ data = stream.recv(1024)
57
+ end
58
+ #puts "return_value is : #{return_value}"
59
+ #puts "data length is : #{data.length}"
60
+ end
61
+ end
62
+
63
+ # If received data is less than 1024 characters or for last data
64
+ # we read in the above loop
65
+ #return_value += data
66
+
67
+ # Get the command prompt inserted by JSSH
68
+ #s = Kernel.select([socket] , nil , nil, 0.3)
69
+
70
+ #if(s != nil)
71
+ # for stream in s[0]
72
+ # return_value += socket.recv(1024)
73
+ # end
74
+ #end
75
+
76
+ length = return_value.length
77
+ #puts "Return value before removing command prompt is : #{return_value}"
78
+
79
+ #Remove the command prompt. Every result returned by JSSH has "\n> " at the end.
80
+ if length <= 3
81
+ return_value = ""
82
+ elsif(return_value[0..2] == "\n> ")
83
+ return_value = return_value[3..length-1]
84
+ else
85
+ #return_value = return_value[0..length-3]
86
+ return_value = return_value[0..length-4]
87
+ end
88
+ #puts "Return value after removing command prompt is : #{return_value}"
89
+ #socket.flush
90
+
91
+ # make sure that command prompt doesn't get there.
92
+ if(return_value[return_value.length - 3..return_value.length - 1] == "\n> ")
93
+ return_value = return_value[0..return_value.length - 4]
94
+ end
95
+ if(return_value[0..2] == "\n> ")
96
+ return_value = return_value[3..return_value.length - 1]
97
+ end
98
+ #puts "return value is : #{return_value}"
99
+ return return_value
100
+ end
101
+ end
@@ -0,0 +1,5 @@
1
+ module FireWatir
2
+ class Firefox
3
+ VERSION = '1.6.5'
4
+ end
5
+ end
@@ -0,0 +1,122 @@
1
+ if /linux/i.match(RUBY_PLATFORM)
2
+ require File.expand_path(File.join(File.dirname(__FILE__), 'x11'))
3
+
4
+ # Linux/X11 implementation of WinClicker.
5
+ # Not all functionality is present because of the differences between X11
6
+ # and Win32.
7
+ class WinClicker
8
+
9
+ def clickJavaScriptDialog(button="OK")
10
+ click_window_button(/The page/,button)
11
+ end
12
+
13
+ def clickJSDialog_Thread(button="OK")
14
+ puts "clickJSDialog_Thread Starting waiting..."
15
+ sleep 3
16
+ puts " clickJSDialog_Thread ... resuming"
17
+ n = 0
18
+ while n < 3
19
+ sleep 1
20
+ click_window_button(/The page/,button)
21
+ end
22
+ end
23
+
24
+ def clearSecurityAlertBox
25
+ click_window_button(/Unknown Authority/, "OK")
26
+ click_window_button(/Domain Name Mismatch/, "Cancel")
27
+ end
28
+
29
+ def clickWindowsButton(title, button, maxWaitTime=30)
30
+ start = Time.now
31
+ w = window_by_title(title)
32
+ until w || (Time.now - start > maxWaitTime)
33
+ sleep(2) # Window search is pretty CPU intensive, so relax the requirement
34
+ w = window_by_title(title)
35
+ end
36
+ unless w
37
+ puts "clickWindowsButton: Cant make window active in specified time ( " + maxWaitTime.to_s + ") - no handle"
38
+ return false
39
+ end
40
+ click_button(w,button)
41
+ end
42
+
43
+ private
44
+
45
+ # Since it's impossible to read the button text in X11 windows,
46
+ # we have to specify keystrokes for the button names given the title.
47
+ # TODO: A more elegant solution, or expand this list (to fill out popup text boxes for basic HTTP auth, perhaps).
48
+ @@window_keys = [
49
+ [/Unknown Authority/i, {'ok' => [:enter], 'cancel' => [:tab,:tab,:tab,:enter]}],
50
+ [/Domain Name Mismatch/i, {'ok' => [:tab, :enter], 'cancel' => [:enter]}],
51
+ [/Opening/i, {'ok' => [:sleep,:enter], 'cancel' => [:tab,:tab,:tab,:enter]}],
52
+ [/The page at .* says/i, {'ok' => [:enter], 'cancel' => [:tab,:enter]}]
53
+ ]
54
+
55
+ # Collection of all current firefox windows
56
+ def firefox_windows(w = nil)
57
+ collection = []
58
+ windows = nil
59
+ if w
60
+ windows = [w]
61
+ else
62
+ windows = X11::Display.instance.screens.collect{|s| s.root_window}
63
+ end
64
+ windows.each do |window|
65
+ if window.class == 'Gecko'
66
+ collection << window
67
+ end
68
+ window.children.each do |c|
69
+ collection << firefox_windows(c)
70
+ end
71
+ end
72
+ return collection.flatten.compact
73
+ end
74
+
75
+ def window_by_title(title,windows=nil)
76
+ pattern = nil
77
+ if title.is_a?(Regexp)
78
+ pattern = title
79
+ else
80
+ pattern = Regexp.compile(title,Regexp::IGNORECASE)
81
+ end
82
+ windows ||= X11::Display.instance.screens.collect{|s| s.root_window}
83
+ if window = windows.find{|w| w.class == 'Gecko' && pattern.match(w.name)}
84
+ return window
85
+ else
86
+ children = windows.reject{|w| w.class == 'Gecko'}.collect{|w| w.children}.flatten.compact
87
+ if children.length > 0
88
+ return window_by_title(pattern,children)
89
+ end
90
+ end
91
+ return nil
92
+ end
93
+
94
+ def keystrokes(window,button)
95
+ keys = @@window_keys.find{|wk| wk.first.match(window.name)}
96
+ if keys
97
+ return keys.last[button.downcase]
98
+ else
99
+ return false
100
+ end
101
+ end
102
+
103
+ def click_button(window, button)
104
+ keys = nil
105
+ if button.is_a?(Symbol)
106
+ keys = [button]
107
+ else
108
+ keys = keystrokes(window,button)
109
+ end
110
+ return unless keys
111
+ keys.each do |key|
112
+ if key == :sleep
113
+ @sleep_next = 1
114
+ next
115
+ end
116
+ window.send_key(key,@sleep_next)
117
+ @sleep_next = nil
118
+ end
119
+ end
120
+
121
+ end
122
+ end
@@ -0,0 +1,192 @@
1
+ require 'dl/import'
2
+ require 'dl/struct'
3
+
4
+ require 'singleton'
5
+
6
+ module X11
7
+ class << self
8
+ include X11 # Do this so we can call imported libraries directly on X11
9
+ end
10
+
11
+ # Load the X11 library
12
+ extend DL::Importable
13
+ dlload "libX11.so"
14
+
15
+ # Import necessary functions from X11 here.
16
+ import("XOpenDisplay", "unsigned long", ["char*"])
17
+ import("XScreenCount", "int", ["unsigned long"])
18
+ import("XRootWindow", "unsigned long", ["unsigned long","int"])
19
+
20
+ import("XFree", "int", ["void*"])
21
+
22
+ import("XFetchName", "int", ["unsigned long","unsigned long","char**"])
23
+ import("XGetClassHint", "int", ["unsigned long","unsigned long","void*"])
24
+ import("XQueryTree", "int", ["unsigned long","unsigned long","unsigned long*","unsigned long*","unsigned long**","unsigned int*"])
25
+
26
+ import("XSetInputFocus", "int", ["unsigned long","unsigned long","int","long"])
27
+ import("XSendEvent", "int", ["unsigned long","unsigned long","int","long","void*"])
28
+ import("XFlush", "int", ["unsigned long"])
29
+
30
+ # Structs we will use in API calls.
31
+ # Pointer structs are necessary when the API uses a pointer parameter for a return value.
32
+ ULPPointer = struct [
33
+ "long* value"
34
+ ]
35
+ ULPointer = struct [
36
+ "long value"
37
+ ]
38
+ CPPointer = struct [
39
+ "char* value"
40
+ ]
41
+ UIPointer = struct [
42
+ "int value"
43
+ ]
44
+ # Info about window class
45
+ XClassHint = struct [
46
+ "char* res_name",
47
+ "char* res_class"
48
+ ]
49
+ # Event struct for key presses
50
+ XKeyEvent = struct [
51
+ "int type",
52
+ "long serial",
53
+ "int send_event",
54
+ "long display",
55
+ "long window",
56
+ "long root",
57
+ "long subwindow",
58
+ "long time",
59
+ "int x",
60
+ "int y",
61
+ "int x_root",
62
+ "int y_root",
63
+ "int state",
64
+ "int keycode",
65
+ "int same_screen"
66
+ ]
67
+
68
+ # End of library imports.
69
+
70
+ # X11 Display. Singleton -- assumes single display.
71
+ # Assumes the current display is the same as the one running FireFox.
72
+ # Represented by memory pointer (which we treat in-code as an unsigned long).
73
+ class Display
74
+ include Singleton
75
+
76
+ def initialize
77
+ @xdisplay = X11.xOpenDisplay("");
78
+ end
79
+
80
+ # Array of screens associated with this display.
81
+ def screens
82
+ nScreens = X11.xScreenCount(@xdisplay);
83
+ (0...nScreens).collect{|n| Screen.new(n,@xdisplay)}
84
+ end
85
+ end
86
+
87
+ # A display screen, for multi-monitor displays like mine ;-)
88
+ # Represented by display pointer and screen number.
89
+ class Screen
90
+ def initialize(screen_num,xdisplay)
91
+ @screen_num = screen_num
92
+ @xdisplay = xdisplay
93
+ end
94
+
95
+ # Root window containing all other windows in this screen.
96
+ def root_window
97
+ Window.new(X11.xRootWindow(@xdisplay,@screen_num),@screen_num,@xdisplay)
98
+ end
99
+ end
100
+
101
+ # An X11 Window (toplevel window, widget, applet, etc.)
102
+ # Represented by its XID, an unsigned long.
103
+ class Window
104
+ attr_reader :xid, :name, :class, :hint, :parent
105
+
106
+ def initialize(xid,screen_num,xdisplay,parent=nil)
107
+ @xid = xid
108
+ @screen_num = screen_num
109
+ @xdisplay = xdisplay
110
+ @parent = parent
111
+ load_standard
112
+ end
113
+
114
+ # Child windows
115
+ def children
116
+ tree[:children].collect{|c| Window.new(c,@screen_num,@xdisplay,self)}
117
+ end
118
+
119
+ # XID of parent window
120
+ def parent_xid
121
+ parent ? parent.xid : nil
122
+ end
123
+
124
+ # Send a key press to this window
125
+ def send_key(key=:enter,sleep=nil)
126
+ # TODO expand this list out, add support for shift, etc.
127
+ @@keys = {:enter => 36, :tab => 23} unless defined?@@keys
128
+ keycode = @@keys[key]
129
+ X11.xSetInputFocus(@xdisplay, @xid, 1, 0)
130
+ sleep(sleep) if sleep
131
+ e = create_key_event
132
+ e.keycode = keycode
133
+ e.type = 2 # press
134
+ X11.xSendEvent(@xdisplay,@xid,1,1,e)
135
+ e.type = 3 # release
136
+ X11.xSendEvent(@xdisplay,@xid,1,2,e)
137
+ X11.xFlush(@xdisplay)
138
+ end
139
+
140
+ private
141
+
142
+ # Retrieve this window's portion of the window tree
143
+ # Includes display root, parent, and children
144
+ def tree
145
+ tree = {:children => [], :parent => 0, :root => 0}
146
+ children = ULPPointer.malloc
147
+ root = ULPointer.malloc
148
+ parent = ULPointer.malloc
149
+ n = UIPointer.malloc
150
+ r=X11.xQueryTree(@xdisplay,@xid,root,parent,children,n)
151
+ tree[:parent] = parent.value
152
+ tree[:root] = root.value
153
+ tree[:children] = children.value.to_s(4*n.value).unpack("L*") if children.value
154
+ tree
155
+ end
156
+
157
+ # Load some standard attributes (name and class)
158
+ def load_standard
159
+ name = CPPointer.malloc
160
+ if X11.xFetchName(@xdisplay,@xid,name) != 0
161
+ @name = name.value.to_s
162
+ X11.xFree name.value
163
+ end
164
+ classHint = XClassHint.malloc
165
+ res = X11.xGetClassHint(@xdisplay,@xid,classHint)
166
+ if res != 0 then
167
+ @class = classHint.res_name.to_s
168
+ @hint = classHint.res_class.to_s
169
+ X11.xFree classHint.res_name
170
+ X11.xFree classHint.res_class
171
+ end
172
+ end
173
+
174
+ # Create an X11 Key Event for this window and set defaults
175
+ def create_key_event
176
+ ke = XKeyEvent.malloc
177
+ ke.serial = 0
178
+ ke.send_event = 1
179
+ ke.display = @xdisplay
180
+ ke.window = @xid
181
+ ke.subwindow = 0
182
+ ke.root = tree[:root]
183
+ ke.time = Time.now.sec
184
+ ke.state = 0
185
+ ke.same_screen = 0
186
+ return ke
187
+ end
188
+
189
+ end
190
+
191
+ end
192
+
@@ -0,0 +1,49 @@
1
+ # feature tests for attaching to new Firefox windows
2
+ # revision: $Revision: 1.0 $
3
+
4
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..') unless $SETUP_LOADED
5
+ require 'unittests/setup'
6
+
7
+ class TC_NewWindow < Test::Unit::TestCase
8
+ tags :fails_on_ie
9
+
10
+ def setup
11
+ goto_page("new_browser.html")
12
+ end
13
+
14
+ def test_simply_attach_to_new_window_using_title
15
+ browser.link(:text, 'New Window').click
16
+ begin
17
+ ff_new = browser.attach(:title, 'Pass Page')
18
+ rescue Watir::Exception::NoMatchingWindowFoundException
19
+ raise $!, "Attach failed, check your Firefox settings: http://wiki.openqa.org/display/WTR/FireWatir+Installation#FireWatirInstallation-ffsettings"
20
+ end
21
+ assert(ff_new.text.include?('PASS'))
22
+ ff_new.close
23
+ #browser.link(:text, 'New Window').click
24
+ end
25
+
26
+ def test_simply_attach_to_new_window_using_url
27
+ browser.link(:text, 'New Window').click
28
+ begin
29
+ ff_new = browser.attach(:url, /pass\.html/)
30
+ rescue Watir::Exception::NoMatchingWindowFoundException
31
+ raise $!, "Attach failed, check your Firefox settings: http://wiki.openqa.org/display/WTR/FireWatir+Installation#FireWatirInstallation-ffsettings"
32
+ end
33
+ assert(ff_new.text.include?('PASS'))
34
+ ff_new.close
35
+ #browser.link(:text, 'New Window').click
36
+ end
37
+
38
+ def test_attach_to_new_window_with_same_title_as_parent
39
+ browser.link(:text, 'New Browser Window').click
40
+ ff_new = browser.attach(:title, 'New Browser Launcher')
41
+ assert(ff_new.text.include?('PASS'))
42
+ ff_new.close
43
+ end
44
+
45
+ def test_new_window_exists
46
+ assert_raises(NoMatchingWindowFoundException , "NoMatchingWindowFoundException was supposed to be thrown" ) { browser.attach(:title, "missing_title") }
47
+ assert_raises(NoMatchingWindowFoundException , "NoMatchingWindowFoundException was supposed to be thrown" ) { browser.attach(:url, "missing_url") }
48
+ end
49
+ end