A few years back now I used Watir to automate a batch of queries against a horribly archaic ColdFusion intranet site. I used Watir as this site absolutely required Internet Explorer and so Mechanize, my preferred port of call, was not an option. The intranet site in question would helpfully popup not just one, but two, confirmation windows to let you know a query had failed to find a result, that then had to be manually clicked (initially, at least) through in order for the script to continue with the next query.

At the time (Ruby 1.8.X, Windows XP, IE6) the best option (for me) for handling these popups in an automated fashion was using AutoItx3:

#Be careful as actually targets whatever application is in front. Need to be hands off with this. But DOES WORK.
def check_for_popups # Number 2 from http://wiki.openqa.org/display/WTR/JavaScript+Pop+Ups
	autoit = WIN32OLE.new('AutoItX3.Control')
	#
	# Do forever - assumes popups could occur anywhere/anytime in your application.
	loop do
		# Look for window with given title. Give up after 1 second.
		ret = autoit.WinWait('Message from webpage', '', 1)
		#
		# If window found, send appropriate keystroke (e.g. {enter}, {Y}, {N}).
		if (ret==1) then autoit.Send('{enter}') end
		#
		# Take a rest to avoid chewing up cycles and give another thread a go.
		# Then resume the loop.
		sleep(1)
	end
end

and running it inside its own thread:

$popup = Thread.new { check_for_popups }  # start popup handler
at_exit { Thread.kill($popup) }           # kill thread on exit of main application

And this all made sense. Of sorts: Running the popup handler in its own thread behaved exactly as I thought it would and no magic was required.

Sometime later (Ruby 1.9.X, still Windows XP, IE?) and I came across a much easier way of doing things using click_no_wait and javascript_dialog:

ie.cell(:id, "findButton").click_no_wait #no_wait so can kill js popup
sleep 1 #Otherwise it will think search is already complete!
#Then do our own manual waiting loop to deal with the popup
until (ie.text_field(:name, "timeTitle").value == "Search Time =") do
	sleep 1
	#Check for existance of popup
	if ie.javascript_dialog.exists?
		ie.javascript_dialog.button('OK').click
	end
end

This was better, not in that it didn’t require the use of threading, rather that it would target only what it was meant to and not just any window of any application that popped to the front. The use of click_no_wait ensured that Watir didn’t get stuck waiting if a popup appeared and then I just had to monitor the webpage for a change in a text field to know whether the search had finished or not.

Present day (Ruby 2.0.X, Windows 7, IE8) and Watir has evolved a lot since I’d first used it! For whatever reason, click_no_wait no longer works (doesn’t actually ‘click’); arguably the cleanest technique I’d since found, overiding the javascript function, also doesn’t work; javascript_dialog no longer exists; however, there is now a built in Alert class for dealing with the popups (that automatically looks for windows titled such as “Message from webpage”), but because of the two popup windows in quick succession I had to monkey patch the Alert class so I could have a close_no_wait version to avoid it getting stuck after closing the first:

module Watir
	class Alert
		def close_no_wait
			dialog.close
		end
	end
end

Then, using the same approach as I’d used initially, I set up a method which used this to close the popups, which I could call from within a thread:

def check_for_popups
	loop do
		if IE.alert.exists?
			IE.alert.close_no_wait
		end
	end
end

However, this didn’t work; backtracing ultimately lead to a method_missing error, i.e it didn’t know anything about close_no_wait, but it did understand about the higher level object; puts IE.methods worked. After lots of investigation and playing about in irb I found by accident that if I ran the function once first it’d then work in a separate thread.

So ended up making the function like so (pay special attention to my excellent begin and rescue debugging):

def check_for_popups
	loop do
		begin
			puts "begin"
			if IE.alert.exists?
				IE.alert.close_no_wait
			end
		rescue => exception
			puts "rescue"
			puts exception.backtrace
		end
		sleep 1
		#Default number of threads seems to be 2 from a script. In IRB it's 1
		#Weirdly this some how ends up at 4 threads. 
		puts Thread.list.length
		#So it quits itself if not running within a thread
		if Thread.list.length <= 2
			break
		end
	end
end

This uses Thread.list.length to determine whether the method is running inside a thread or not, because if it isn’t then I don’t want it running in a loop. This meant I could call it once as a dummy in main program and then call it again in a thread as intended:

#Need to call the check_for_popups first so it'll work in the thread I DO NOT understand why
check_for_popups
#Then ok to start thread
$popup = Thread.new { check_for_popups } # start popup handler

So this works, but I really don’t understand why it’s needed. I first thought it might have been something to do with monkey patching, but it’s not. I wonder if it’s an oddball Watir thing? Or a Windows’ Ruby thing? As I’ve not been able to reproduce the error using similar techniques on a different platform (obviously not with Watir-classic though).