vapir-ie 1.7.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,60 @@
1
+ require 'win32/process'
2
+ require 'vapir-ie/ie-class'
3
+
4
+ module Vapir
5
+ class IE
6
+ # the version string, from the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Version
7
+ def self.version
8
+ @@ie_version ||= begin
9
+ require 'win32/registry'
10
+ ::Win32::Registry::HKEY_LOCAL_MACHINE.open("SOFTWARE\\Microsoft\\Internet Explorer") do |ie_key|
11
+ ie_key.read('Version').last
12
+ end
13
+ # OR: ::WIN32OLE.new("WScript.Shell").RegRead("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Internet Explorer\\Version")
14
+ end
15
+ end
16
+ # the version string divided into its numeric parts returned as an array of integers
17
+ def self.version_parts
18
+ @@ie_version_parts ||= IE.version.split('.').map{|part| part.to_i }
19
+ end
20
+ class Process
21
+ # Vapir::IE::Process.start is called by Vapir::IE.new_process and does not start a new process correctly in IE8.
22
+ # Calling IE8 with the -nomerge option correctly starts a new process, so call Process.create with this option if
23
+ # IE's version is 8
24
+ def self.start
25
+ program_files = ENV['ProgramFiles'] || "c:\\Program Files"
26
+ startup_command = "#{program_files}\\Internet Explorer\\iexplore.exe"
27
+ startup_command << " -nomerge" if ::Vapir::IE.version_parts.first==8
28
+ # maybe raise an error here if it's > 8, as not-yet-supported? who knows what incompatibilities the future will hold
29
+ process_info = ::Process.create('app_name' => "#{startup_command} about:blank")
30
+ process_id = process_info.process_id
31
+ new process_id
32
+ end
33
+
34
+ def initialize process_id
35
+ @process_id = process_id
36
+ end
37
+ attr_reader :process_id
38
+
39
+ def window
40
+ Waiter.wait_until do
41
+ IE.each do | ie |
42
+ window = ie.ie
43
+ hwnd = ie.hwnd
44
+ process_id = Process.process_id_from_hwnd hwnd
45
+ return window if process_id == @process_id
46
+ end
47
+ end
48
+ end
49
+
50
+ # Returns the process id for the specifed hWnd.
51
+ def self.process_id_from_hwnd hwnd
52
+ pid_info = ' ' * 32
53
+ Win32API.new('user32', 'GetWindowThreadProcessId', 'ip', 'i').
54
+ call(hwnd, pid_info)
55
+ process_id = pid_info.unpack("L")[0]
56
+ end
57
+
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,59 @@
1
+ require 'vapir-ie/element'
2
+ require 'vapir-common/elements/elements'
3
+
4
+ module Vapir
5
+
6
+ # This class is the means of accessing an image on a page.
7
+ # Normally a user would not need to create this object as it is returned by the Vapir::Container#image method
8
+ #
9
+ # many of the methods available to this object are inherited from the Element class
10
+ #
11
+ class IE::Image < IE::Element
12
+ include Vapir::Image
13
+
14
+ dom_attr :fileSize => :file_size
15
+ dom_attr :fileCreatedDate => :file_created_date
16
+
17
+ # This method attempts to find out if the image was actually loaded by the web browser.
18
+ # If the image was not loaded, the browser is unable to determine some of the properties.
19
+ # We look for these missing properties to see if the image is really there or not.
20
+ # If the Disk cache is full (tools menu -> Internet options -> Temporary Internet Files), it may produce incorrect responses.
21
+ def loaded?
22
+ assert_exists do
23
+ !(element_object.fileCreatedDate == "" and element_object.fileSize.to_i == -1)
24
+ end
25
+ end
26
+ alias_deprecated :hasLoaded?, :loaded?
27
+
28
+ # This method saves the image to the file path that is given. The
29
+ # path must be in windows format (c:\\dirname\\somename.gif). This method
30
+ # will not overwrite a previously existing image. If an image already
31
+ # exists at the given path then a dialog will be displayed prompting
32
+ # for overwrite.
33
+ # Raises a VapirException if AutoIt is not correctly installed
34
+ # path - directory path and file name of where image should be saved
35
+ def save(path)
36
+ # TODO: FIX
37
+ require 'vapir-ie/windowhelper'
38
+ WindowHelper.check_autoit_installed
39
+ @container.goto(src)
40
+ begin
41
+ thrd = fill_save_image_dialog(path)
42
+ @container.document.execCommand("SaveAs")
43
+ thrd.join(5)
44
+ ensure
45
+ @container.back
46
+ end
47
+ end
48
+
49
+ def fill_save_image_dialog(path)
50
+ raise NotImplementedError
51
+ #todo: FIX
52
+ Thread.new do
53
+ system("ruby -e \"require 'win32ole'; @autoit=WIN32OLE.new('AutoItX3.Control'); waitresult=@autoit.WinWait 'Save Picture', '', 15; if waitresult == 1\" -e \"@autoit.ControlSetText 'Save Picture', '', '1148', '#{path}'; @autoit.ControlSend 'Save Picture', '', '1', '{ENTER}';\" -e \"end\"")
54
+ end
55
+ end
56
+ private :fill_save_image_dialog
57
+ end
58
+
59
+ end
@@ -0,0 +1,158 @@
1
+ require 'vapir-ie/element'
2
+ require 'vapir-common/elements/elements'
3
+
4
+ module Vapir
5
+
6
+ class IE::InputElement < IE::Element
7
+ include InputElement
8
+ end
9
+
10
+ #
11
+ # Input: Select
12
+ #
13
+
14
+ # This class is the way in which select boxes are manipulated.
15
+ # Normally a user would not need to create this object as it is returned by the Vapir::Container#select_list method
16
+ class IE::SelectList < IE::InputElement
17
+ include SelectList
18
+ end
19
+
20
+ # An item in a select list
21
+ class IE::Option < IE::Element
22
+ include Option
23
+ end
24
+
25
+ #
26
+ # Input: Button
27
+ #
28
+
29
+ # Returned by the Vapir::Container#button method
30
+ class IE::Button < IE::InputElement
31
+ include Button
32
+ dom_attr :value => :caption
33
+ end
34
+
35
+ #
36
+ # Input: Text
37
+ #
38
+
39
+ # This class is the main class for Text Fields
40
+ # Normally a user would not need to create this object as it is returned by the Vapir::Container#text_field method
41
+ class IE::TextField < IE::InputElement
42
+ include TextField
43
+ # def_wrap_guard :size
44
+
45
+ # Returns true if the text field contents is matches the specified target,
46
+ # which can be either a string or a regular expression.
47
+ # Raises UnknownObjectException if the object can't be found
48
+ #
49
+ # TODO: move to common
50
+ def verify_contains(target) # FIXME: verify_contains should have same name and semantics as IE#contains_text (prolly make this work for all elements)
51
+ assert_exists do
52
+ if target.kind_of? String
53
+ return true if self.value == target
54
+ elsif target.kind_of? Regexp
55
+ return true if self.value.match(target) != nil
56
+ end
57
+ return false
58
+ end
59
+ end
60
+
61
+ # Drag the entire contents of the text field to another text field
62
+ # 19 Jan 2005 - It is added as prototype functionality, and may change
63
+ # * destination_how - symbol, :id, :name how we identify the drop target
64
+ # * destination_what - string or regular expression, the name, id, etc of the text field that will be the drop target
65
+ def drag_contents_to(destination_how, destination_what)
66
+ assert_exists do
67
+ destination = @container.text_field!(destination_how, destination_what)
68
+
69
+ element_object.focus
70
+ element_object.select
71
+ value = self.value
72
+
73
+ with_highlight do
74
+ fire_event("onSelect")
75
+ fire_event("ondragstart")
76
+ fire_event("ondrag")
77
+ destination.with_highlight do
78
+ destination.fire_event("onDragEnter")
79
+ destination.fire_event("onDragOver")
80
+ destination.fire_event("ondrop")
81
+ destination.value = destination.value + value.to_s
82
+ end
83
+ fire_event("ondragend")
84
+ self.value = ""
85
+ end
86
+
87
+ end
88
+ end
89
+ alias_deprecated :dragContentsTo, :drag_contents_to
90
+
91
+ def requires_typing
92
+ @type_keys = true
93
+ self
94
+ end
95
+ def abhors_typing
96
+ @type_keys = false
97
+ self
98
+ end
99
+ end
100
+
101
+ # this class can be used to access hidden field objects
102
+ # Normally a user would not need to create this object as it is returned by the Vapir::Container#hidden method
103
+ class IE::Hidden < IE::TextField
104
+ include Hidden
105
+ end
106
+
107
+ # For fields that accept file uploads
108
+ # Windows dialog is opened and handled by WinWindow (see scripts/select_file.rb), launched in a new process.
109
+ class IE::FileField < IE::InputElement
110
+ include FileField
111
+
112
+ # set the file location in the Choose file dialog
113
+ def set(file_path)
114
+ assert_exists do
115
+ # it would be nice to do a click_no_wait and then enter the select file dialog information
116
+ # in the same thread, but that won't work here, because #click_no_wait runs in a javascript
117
+ # setTimeout, and javascript calling to a file input's .click() method doesn't work. it appears
118
+ # to work until you submit the form, at which point it says access is denied. so, the click has
119
+ # to be done via WIN32OLE, but it doesn't return until the file field is set, so we need two
120
+ # ruby processes (since WIN32OLE blocking blocks all ruby threads).
121
+ # since locating this element is a much more complicated task than locating the enabled_popup
122
+ # of this browser, this process will handle the former, and we'll spawn another to do the
123
+ # latter.
124
+ require 'win32/process'
125
+ require 'vapir-common/win_window'
126
+ rubyw_exe= File.join(Config::CONFIG['bindir'], 'rubyw')
127
+ error_file_name=File.expand_path(File.join(File.dirname(__FILE__), 'scripts', 'select_file_error_status.marshal_dump'))
128
+ select_file_script=File.expand_path(File.join(File.dirname(__FILE__), 'scripts', 'select_file.rb'))
129
+ command_line=rubyw_exe+[select_file_script, browser.hwnd.to_s, file_path, error_file_name].map{|arg| " \"#{arg.gsub("/", "\\")}\""}.join('')
130
+ # TODO/FIX: the above method of escaping seems to have issues with trailing slashes.
131
+ select_file_process=::Process.create('command_line' => command_line)
132
+
133
+ click
134
+
135
+ if ::Waiter.try_for(2, :exception => nil) { File.exists?(error_file_name) } # wait around a moment for the script to finish writing - #click returns before that script exits
136
+ marshaled_error=File.read(error_file_name)
137
+ error=Marshal.load(marshaled_error)
138
+ error[:backtrace]+= caller(0)
139
+ File.delete(error_file_name)
140
+ raise error[:class], error[:message], error[:backtrace]
141
+ end
142
+ return file_path
143
+ # TODO/FIX: figure out what events ought to be fired here - onchange, maybe others
144
+ end
145
+ end
146
+ end
147
+
148
+ # This class is the watir representation of a radio button.
149
+ class IE::Radio < IE::InputElement
150
+ include Radio
151
+ end
152
+
153
+ # This class is the watir representation of a check box.
154
+ class IE::CheckBox < IE::InputElement
155
+ include CheckBox
156
+ end
157
+
158
+ end
@@ -0,0 +1,23 @@
1
+ require 'vapir-ie/element'
2
+ require 'vapir-common/elements/elements'
3
+
4
+ module Vapir
5
+
6
+ # This class is the means of accessing a link on a page
7
+ # Normally a user would not need to create this object as it is returned by the Vapir::Container#link method
8
+ # many of the methods available to this object are inherited from the Element class
9
+ #
10
+ class IE::Link < IE::Element
11
+ include Vapir::Link
12
+
13
+ # if an image is used as part of the link, this will return true
14
+ def link_has_image
15
+ images.length > 0
16
+ end
17
+
18
+ def src
19
+ raise NotImplementedError, "Link#src is gone. use Link#images to get a collection of images from which you may get the #src attribute"
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,21 @@
1
+ require 'logger'
2
+
3
+ module Vapir
4
+ class VapirLogger < Logger
5
+ def initialize(filName, logsToKeep, maxLogSize)
6
+ super(filName, logsToKeep, maxLogSize)
7
+ self.level = Logger::DEBUG
8
+ self.datetime_format = "%d-%b-%Y %H:%M:%S"
9
+ self.debug("Vapir starting")
10
+ end
11
+ end
12
+
13
+ class DefaultLogger < Logger
14
+ def initialize
15
+ super(STDERR)
16
+ self.level = Logger::WARN
17
+ self.datetime_format = "%d-%b-%Y %H:%M:%S"
18
+ self.info "Log started"
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,224 @@
1
+ require 'vapir-common/win_window'
2
+ require 'vapir-common/modal_dialog'
3
+ require 'vapir-ie/page_container'
4
+ require 'Win32API'
5
+
6
+ module Vapir
7
+ class IE::ModalDialog
8
+ include Vapir::ModalDialog
9
+ def locate
10
+ @modal_window=@browser.win_window.enabled_popup
11
+ end
12
+
13
+ def exists?
14
+ @modal_window && @modal_window.exists?
15
+ end
16
+
17
+ def text
18
+ assert_exists
19
+ @modal_window.children.select{|child| child.class_name.downcase=='static' && child.text!=''}.map{|c| c.text }.join(' ')
20
+ end
21
+
22
+ def set_text_field(value)
23
+ assert_exists
24
+ edit_field=@modal_window.children.detect{|child| child.class_name=='Edit'} || (raise "No Edit field in the popup!")
25
+ edit_field.send_set_text!(value)
26
+ value
27
+ end
28
+
29
+ def click_button(button_text, options={})
30
+ assert_exists
31
+ options=handle_options(options, :timeout => ModalDialog::DEFAULT_TIMEOUT)
32
+ @modal_window.click_child_button_try_for!(button_text, options[:timeout])
33
+ end
34
+
35
+ def close
36
+ if (document=IE::ModalDialogDocument.new(self, :error => false, :timeout => 0)) && document.exists?
37
+ document.close
38
+ else
39
+ @modal_window.send_close!
40
+ end
41
+ ::Waiter.try_for(ModalDialog::DEFAULT_TIMEOUT, :exception => Vapir::Exception::WindowException.new("The modal window failed to close")) do
42
+ !exists?
43
+ end
44
+ end
45
+
46
+ def hwnd
47
+ assert_exists
48
+ @modal_window.hwnd
49
+ end
50
+ def win_window
51
+ @modal_window
52
+ end
53
+
54
+ def document
55
+ assert_exists
56
+ IE::ModalDialogDocument.new(self)
57
+ end
58
+ end
59
+ class IE::ModalDialogDocument
60
+ include IE::PageContainer
61
+ @@iedialog_file = (File.expand_path(File.dirname(__FILE__) + '/..') + "/vapir-ie/IEDialog/Release/IEDialog.dll").gsub('/', '\\')
62
+
63
+ GetUnknown = Win32API.new(@@iedialog_file, 'GetUnknown', ['l', 'p'], 'v')
64
+ def initialize(containing_modal_dialog, options={})
65
+ options=handle_options(options, :timeout => ModalDialog::DEFAULT_TIMEOUT, :error => true)
66
+ @containing_modal_dialog=containing_modal_dialog
67
+
68
+ intUnknown = nil
69
+ ::Waiter.try_for(options[:timeout], :exception => (options[:error] && "Unable to attach to Modal Window after #{options[:timeout]} seconds.")) do
70
+ intPointer = [0].pack("L") # will contain the int value of the IUnknown*
71
+ GetUnknown.call(@containing_modal_dialog.hwnd, intPointer)
72
+ intArray = intPointer.unpack('L')
73
+ intUnknown = intArray.first
74
+ intUnknown > 0
75
+ end
76
+ if intUnknown && intUnknown > 0
77
+ @document_object = WIN32OLE.connect_unknown(intUnknown)
78
+ end
79
+ end
80
+ attr_reader :containing_modal_dialog
81
+ attr_reader :document_object
82
+ def locate!(options={})
83
+ exists? || raise(Vapir::Exception::NoMatchingWindowFoundException, "The modal dialog seems to have stopped existing.")
84
+ end
85
+
86
+ def exists?
87
+ # todo/fix: will the document object change / become invalid / need to be relocated?
88
+ @document_object && @containing_modal_dialog.exists?
89
+ end
90
+
91
+ # this looks for a modal dialog on this modal dialog. but really it's modal to the same browser window
92
+ # that this is modal to, so we will check for the modal on the browser, see if it isn't the same as our
93
+ # self, and return it if so.
94
+ def modal_dialog(options={})
95
+ ::Waiter.try_for(ModalDialog::DEFAULT_TIMEOUT,
96
+ :exception => NoMatchingWindowFoundException.new("No other modal dialog was found on the browser."),
97
+ :condition => proc{|md| md.hwnd != containing_modal_dialog.hwnd }
98
+ ) do
99
+ modal_dialog=containing_modal_dialog.browser.modal_dialog(options)
100
+ end
101
+ end
102
+ end
103
+ end
104
+ =begin
105
+ module Watir
106
+ class IE::ModalDialog
107
+ include IE::Container
108
+ include IE::PageContainer
109
+ include Win32
110
+
111
+ # Return the current window handle
112
+ attr_reader :hwnd
113
+
114
+ def find_modal_from_window
115
+ # Use handle of our parent window to see if we have any currently
116
+ # enabled popup.
117
+ hwnd = @container.hwnd
118
+ hwnd_modal = 0
119
+ begin
120
+ Watir::until_with_timeout do
121
+ hwnd_modal, arr = GetWindow.call(hwnd, GW_ENABLEDPOPUP) # GW_ENABLEDPOPUP = 6
122
+ hwnd_modal > 0
123
+ end
124
+ rescue TimeOutException
125
+ return nil
126
+ end
127
+ if hwnd_modal == hwnd || hwnd_modal == 0
128
+ hwnd_modal = nil
129
+ end
130
+ @hwnd = hwnd_modal
131
+ end
132
+ private :find_modal_from_window
133
+
134
+ def locate
135
+ how = @how
136
+ what = @what
137
+
138
+ case how
139
+ when nil
140
+ unless find_modal_from_window
141
+ raise NoMatchingWindowFoundException,
142
+ "Modal Dialog not found. Timeout = #{Watir::IE.attach_timeout}"
143
+ end
144
+ when :title
145
+ case what.class.to_s
146
+ # TODO: re-write like WET's so we can select on regular expressions too.
147
+ when "String"
148
+ begin
149
+ Watir::until_with_timeout do
150
+ title = "#{what} -- Web Page Dialog"
151
+ @hwnd, arr = FindWindowEx.call(0, 0, nil, title)
152
+ @hwnd > 0
153
+ end
154
+ rescue TimeOutException
155
+ raise NoMatchingWindowFoundException,
156
+ "Modal Dialog with title #{what} not found. Timeout = #{Watir::IE.attach_timeout}"
157
+ end
158
+ else
159
+ raise ArgumentError, "Title value must be String"
160
+ end
161
+ else
162
+ raise ArgumentError, "Only null and :title methods are supported"
163
+ end
164
+
165
+ intUnknown = 0
166
+ begin
167
+ Watir::until_with_timeout do
168
+ intPointer = " " * 4 # will contain the int value of the IUnknown*
169
+ GetUnknown.call(@hwnd, intPointer)
170
+ intArray = intPointer.unpack('L')
171
+ intUnknown = intArray.first
172
+ intUnknown > 0
173
+ end
174
+ rescue TimeOutException => e
175
+ raise NoMatchingWindowFoundException,
176
+ "Unable to attach to Modal Window #{what.inspect} after #{e.duration} seconds."
177
+ end
178
+
179
+ copy_test_config @parent_container
180
+ @document = WIN32OLE.connect_unknown(intUnknown)
181
+ end
182
+
183
+ def initialize(container, how, what=nil)
184
+ set_container container
185
+ @how = how
186
+ @what = what
187
+ @parent_container = container
188
+ # locate our modal dialog's Document object and save it
189
+ begin
190
+ locate
191
+ rescue NoMethodError => e
192
+ message =
193
+ "IE#modal_dialog not supported with the current version of Ruby (#{RUBY_VERSION}).\n" +
194
+ "See http://jira.openqa.org/browse/WTR-2 for details.\n" +
195
+ e.message
196
+ raise NoMethodError.new(message)
197
+ end
198
+ end
199
+
200
+ def document
201
+ @document
202
+ end
203
+
204
+ # Return the title of the document
205
+ def title
206
+ document.title
207
+ end
208
+
209
+ def attach_command
210
+ "Watir::IE.find(:hwnd, #{@container.hwnd}).modal_dialog"
211
+ end
212
+
213
+ def wait(options={})
214
+ end
215
+
216
+ # Return true if the modal exists. Mostly this is useful for testing whether
217
+ # a modal has closed.
218
+ def exists?
219
+ Watir::Win32::window_exists? @hwnd
220
+ end
221
+ alias :exist? :exists?
222
+ end
223
+ end
224
+ =end