J
jeffz_2002
(long post!)
Hello, I'm creating a little helper class for Watir that can read the
text from an IE Javascript popup and click buttons. It works great for
popups that are created by links. E.g., for the following HTML:
<test_html>
<script language="Javascript">
function showAlert() { alert("Alert showing!"); }
</script>
<p>Link:<br><a href="javascript:showAlert();")'>Click this link</a></p>
</test_html>
I can put the following in a Watir script:
<link_code>
require 'watir'
@ie = Watir::IE.new
@ie.goto("file://C:/test.html")
puts "Working with popup from links:"
jsh = JavascriptPopupHandler.new(@ie, 'OK')
jsh.pauseDuration = 0.1
jsh.handle { @ie.linktext, "Click this link").click }
puts "Here's the text that was showing in the popup: #{jsh.text}"
</link_code>
The above code outputs:
<output>
Working with popup from links:
Here's the text that was showing in the popup: Alert showing!
</output>
The jsh.handle starts a monitor thread that looks for the Javascript
popup, and then executes the block. When it finds a popup, it can pull
the text out of the popup and click the appropriate button (by the
button caption). It works when I pass in a link click in the block.
The code doesn't work for form buttons though, and I can't figure out
why. E.g., for the following html:
<form name="f1" method="post" action="test.html"
onsubmit="javascript:showAlert()">
<input type="submit" name="submit" value="Click this button" />
</form>
The following doesn't work:
<form_watir_code>
# This next call hangs when the popup pops up.
puts "from button:"
jsh.handle { @ie.buttonvalue, "Click this button").click }
puts "Here's the text that was showing in the popup: #{jsh.text}"
</form_watir_code>
This is a bit annoying, and it might be easily fixable ... I was hoping
someone might have some ideas about how to fix it.
Here's the scratch code:
===========================================
require 'watir/winClicker.rb'
# Need to redefine the supplied getWindowHandle in Winclicker
class WinClicker
# Stop printing to console.
def puts(s)
# nothing
end
# getWindowHandle
# Purpose: return the handle to the window with desired title and
class.
# Returns -1 if no match.
#
# Code is taken from winClicker.rb and modified.
# Note: Needed to redefine getWindowHandle, since it returns a window
with
# a caption that matches using a regex, instead of an exact match.
#
def getWindowHandle(title, winclass = "" )
winclass.strip!
# Callbacks
callback_enum_windows = @User32['EnumWindows', 'IPL']
callback_get_class_name = @User32['GetClassName', 'ILpI']
callback_get_caption_length = @User32['GetWindowTextLengthA' ,'LI'
]
# format here - return value type (Long) followed by parameter
types - int in this case -
# see
http://www.ruby-lang.org/cgi-bin/cvsweb.cgi/~checkout~/ruby/ext/dl/doc/dl.txt?
callback_get_caption = @User32['GetWindowTextA', 'iLsL' ]
len = 32 # seemingly arbitrary number
buff = " " * len
bContinueEnum = -1
# Main callback - block of code to execute for all open windows.
callback_enum_windows_proc = DL.callback('ILL') do |hwnd,lparam|
# sleep 0.05 <-- original code had sleep in here, not sure why
....
r, rs = callback_get_class_name.call(hwnd, buff, buff.size)
found_win_class = rs[1].to_s.strip
if ( winclass == "") or ( found_win_class == winclass )
# Get the caption (allocate buffer space, then load)
caption_length, a = callback_get_caption_length.call(hwnd)
captionBuffer = " " * (caption_length + 1)
t, textCaption = callback_get_caption.call(hwnd,
captionBuffer, caption_length + 1)
the_caption = textCaption[1].to_s
return hwnd if (title == the_caption)
end
bContinueEnum # return value
end # do
# execute the callback for all open windows.
r,rs = callback_enum_windows.call(callback_enum_windows_proc, 0)
return bContinueEnum
end
end
# end WinClicker redefinition
class JavascriptPopupHandler
JS_POPUP_TITLE = "Microsoft Internet Explorer"
DEFAULT_PAUSE_BEFORE_FINDING_WINDOW_DURATION = 0.8
def initialize(parent_ie_session, caption_of_button_to_push)
@parent_hwnd = parent_ie_session.ie.hwnd
@caption_of_button_to_push = caption_of_button_to_push
@handle_was_called = false
@popup_text = nil
@pause_before_finding_popup =
DEFAULT_PAUSE_BEFORE_FINDING_WINDOW_DURATION
end
def pauseDuration=(duration =
DEFAULT_PAUSE_BEFORE_FINDING_WINDOW_DURATION)
raise "Duration must be >=0" if (duration < 0)
@pause_before_finding_popup = duration
end
# handle
# Does the action which displays the popup, then gets the popup
# text and clicks the appropriate button.
def handle( &action )
@handle_was_called = true
# Calling the action blocks until the popup dialog box is closed,
# so we need to create a thread that looks out for the dialog box
# before the action is executed.
Thread.new do
sleep @pause_before_finding_popup
wc = WinClicker.new
javascriptPopupHwnd = wc.getWindowHandle(JS_POPUP_TITLE)
raise "No popup matching #{JS_POPUP_TITLE} found" if
(javascriptPopupHwnd == -1)
raise "Got wrong popup?" if (wc.getParent(javascriptPopupHwnd) !=
@parent_hwnd)
# Get the button
button_hwnd = wc.getChildHandle(javascriptPopupHwnd,
@caption_of_button_to_push)
raise "Can't find button #{@caption_of_button_to_push}" if
(button_hwnd == -1)
# Store info about the popup.
@popup_text = wc.getStaticText_hWnd(javascriptPopupHwnd)
# Click the button to continue.
wc.clickButtonWithHandle(button_hwnd)
end
# The thread is now looking for a popup dialog, so when we do
# the action and the dialog box appears, the thread will
# pick it up.
action.call
end
# After the action has occurred, and the handler has clicked
# the appropriate button, we can get information about the popup.
def text
raise "Handle not called yet" if (@handle_was_called == false)
@popup_text
end
end
require 'watir'
@ie = Watir::IE.new
@ie.goto("file://C:/test.html")
puts "Working with popup from links:"
jsh = JavascriptPopupHandler.new(@ie, 'OK')
jsh.pauseDuration = 0.1
jsh.handle { @ie.linktext, "Click this link").click }
puts "Here's the text that was showing in the popup: #{jsh.text}"
# This next call hangs when the popup pops up.
puts "from button:"
jsh.handle { @ie.buttonvalue, "Click this button").click }
puts "Here's the text that was showing in the popup: #{jsh.text}"
@ie.close
===========================================
Here's the test HTML file:
===========================================
<html>
<head>
<title>testing</title>
</head>
<script language="Javascript">
function showAlert() { alert("Alert showing!"); }
</script>
<body>
<h1>testing</h1>
<p>Handler can deal with the link:<br>
<a href="javascript:showAlert();")'>Click this link</a></p>
<hr>
<p>Handler can't deal with the form submit button:<br>
<form name="f1" method="post" action="test.html"
onsubmit="javascript:showAlert()">
<input type="submit" name="submit" value="Click this button" />
</form>
</body>
</html>
===========================================
Any insight would be appreciated!
Jeff
Hello, I'm creating a little helper class for Watir that can read the
text from an IE Javascript popup and click buttons. It works great for
popups that are created by links. E.g., for the following HTML:
<test_html>
<script language="Javascript">
function showAlert() { alert("Alert showing!"); }
</script>
<p>Link:<br><a href="javascript:showAlert();")'>Click this link</a></p>
</test_html>
I can put the following in a Watir script:
<link_code>
require 'watir'
@ie = Watir::IE.new
@ie.goto("file://C:/test.html")
puts "Working with popup from links:"
jsh = JavascriptPopupHandler.new(@ie, 'OK')
jsh.pauseDuration = 0.1
jsh.handle { @ie.linktext, "Click this link").click }
puts "Here's the text that was showing in the popup: #{jsh.text}"
</link_code>
The above code outputs:
<output>
Working with popup from links:
Here's the text that was showing in the popup: Alert showing!
</output>
The jsh.handle starts a monitor thread that looks for the Javascript
popup, and then executes the block. When it finds a popup, it can pull
the text out of the popup and click the appropriate button (by the
button caption). It works when I pass in a link click in the block.
The code doesn't work for form buttons though, and I can't figure out
why. E.g., for the following html:
<form name="f1" method="post" action="test.html"
onsubmit="javascript:showAlert()">
<input type="submit" name="submit" value="Click this button" />
</form>
The following doesn't work:
<form_watir_code>
# This next call hangs when the popup pops up.
puts "from button:"
jsh.handle { @ie.buttonvalue, "Click this button").click }
puts "Here's the text that was showing in the popup: #{jsh.text}"
</form_watir_code>
This is a bit annoying, and it might be easily fixable ... I was hoping
someone might have some ideas about how to fix it.
Here's the scratch code:
===========================================
require 'watir/winClicker.rb'
# Need to redefine the supplied getWindowHandle in Winclicker
class WinClicker
# Stop printing to console.
def puts(s)
# nothing
end
# getWindowHandle
# Purpose: return the handle to the window with desired title and
class.
# Returns -1 if no match.
#
# Code is taken from winClicker.rb and modified.
# Note: Needed to redefine getWindowHandle, since it returns a window
with
# a caption that matches using a regex, instead of an exact match.
#
def getWindowHandle(title, winclass = "" )
winclass.strip!
# Callbacks
callback_enum_windows = @User32['EnumWindows', 'IPL']
callback_get_class_name = @User32['GetClassName', 'ILpI']
callback_get_caption_length = @User32['GetWindowTextLengthA' ,'LI'
]
# format here - return value type (Long) followed by parameter
types - int in this case -
# see
http://www.ruby-lang.org/cgi-bin/cvsweb.cgi/~checkout~/ruby/ext/dl/doc/dl.txt?
callback_get_caption = @User32['GetWindowTextA', 'iLsL' ]
len = 32 # seemingly arbitrary number
buff = " " * len
bContinueEnum = -1
# Main callback - block of code to execute for all open windows.
callback_enum_windows_proc = DL.callback('ILL') do |hwnd,lparam|
# sleep 0.05 <-- original code had sleep in here, not sure why
....
r, rs = callback_get_class_name.call(hwnd, buff, buff.size)
found_win_class = rs[1].to_s.strip
if ( winclass == "") or ( found_win_class == winclass )
# Get the caption (allocate buffer space, then load)
caption_length, a = callback_get_caption_length.call(hwnd)
captionBuffer = " " * (caption_length + 1)
t, textCaption = callback_get_caption.call(hwnd,
captionBuffer, caption_length + 1)
the_caption = textCaption[1].to_s
return hwnd if (title == the_caption)
end
bContinueEnum # return value
end # do
# execute the callback for all open windows.
r,rs = callback_enum_windows.call(callback_enum_windows_proc, 0)
return bContinueEnum
end
end
# end WinClicker redefinition
class JavascriptPopupHandler
JS_POPUP_TITLE = "Microsoft Internet Explorer"
DEFAULT_PAUSE_BEFORE_FINDING_WINDOW_DURATION = 0.8
def initialize(parent_ie_session, caption_of_button_to_push)
@parent_hwnd = parent_ie_session.ie.hwnd
@caption_of_button_to_push = caption_of_button_to_push
@handle_was_called = false
@popup_text = nil
@pause_before_finding_popup =
DEFAULT_PAUSE_BEFORE_FINDING_WINDOW_DURATION
end
def pauseDuration=(duration =
DEFAULT_PAUSE_BEFORE_FINDING_WINDOW_DURATION)
raise "Duration must be >=0" if (duration < 0)
@pause_before_finding_popup = duration
end
# handle
# Does the action which displays the popup, then gets the popup
# text and clicks the appropriate button.
def handle( &action )
@handle_was_called = true
# Calling the action blocks until the popup dialog box is closed,
# so we need to create a thread that looks out for the dialog box
# before the action is executed.
Thread.new do
sleep @pause_before_finding_popup
wc = WinClicker.new
javascriptPopupHwnd = wc.getWindowHandle(JS_POPUP_TITLE)
raise "No popup matching #{JS_POPUP_TITLE} found" if
(javascriptPopupHwnd == -1)
raise "Got wrong popup?" if (wc.getParent(javascriptPopupHwnd) !=
@parent_hwnd)
# Get the button
button_hwnd = wc.getChildHandle(javascriptPopupHwnd,
@caption_of_button_to_push)
raise "Can't find button #{@caption_of_button_to_push}" if
(button_hwnd == -1)
# Store info about the popup.
@popup_text = wc.getStaticText_hWnd(javascriptPopupHwnd)
# Click the button to continue.
wc.clickButtonWithHandle(button_hwnd)
end
# The thread is now looking for a popup dialog, so when we do
# the action and the dialog box appears, the thread will
# pick it up.
action.call
end
# After the action has occurred, and the handler has clicked
# the appropriate button, we can get information about the popup.
def text
raise "Handle not called yet" if (@handle_was_called == false)
@popup_text
end
end
require 'watir'
@ie = Watir::IE.new
@ie.goto("file://C:/test.html")
puts "Working with popup from links:"
jsh = JavascriptPopupHandler.new(@ie, 'OK')
jsh.pauseDuration = 0.1
jsh.handle { @ie.linktext, "Click this link").click }
puts "Here's the text that was showing in the popup: #{jsh.text}"
# This next call hangs when the popup pops up.
puts "from button:"
jsh.handle { @ie.buttonvalue, "Click this button").click }
puts "Here's the text that was showing in the popup: #{jsh.text}"
@ie.close
===========================================
Here's the test HTML file:
===========================================
<html>
<head>
<title>testing</title>
</head>
<script language="Javascript">
function showAlert() { alert("Alert showing!"); }
</script>
<body>
<h1>testing</h1>
<p>Handler can deal with the link:<br>
<a href="javascript:showAlert();")'>Click this link</a></p>
<hr>
<p>Handler can't deal with the form submit button:<br>
<form name="f1" method="post" action="test.html"
onsubmit="javascript:showAlert()">
<input type="submit" name="submit" value="Click this button" />
</form>
</body>
</html>
===========================================
Any insight would be appreciated!
Jeff