vapir-ie 1.7.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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