Here's the way I've found to control IE popups (asking for certificates, asking whether to remember passwords, etc.) on Windows Vista with Watir 1.5.1.1166 and nothing else:
1. Just before sending the click that will generate the popup, popen () a subprocess ("the watcher"). 2. Have the watcher spin, checking for a window with a given title, then send the right keys to dismiss the window. After that, create a file to signal completion and exit. 3. Have the parent process spin, waiting for that file to be created, then continue. I've not succeeded in doing it a simpler way because: 1. Putting the click() and an @autoit.WinWait in different threads always seems to lead to a hang. (I'm guessing I/O is happening when Watir is waiting for the click to finish, so the thread that wants to WinWait never gets started. Or the WinWait thread causes the click thread never to be started.) 2. Windows doesn't support fork() and derivatives, so I can't just fork a watcher, click, and wait for the child to terminate. 3. I can't even have the watcher send the "I'm done" message to its stdout because the parent hangs reading it, presumably for the same reason as threads do. My question is whether I've missed an easier or better way to do this using stock Watir. I'm assuming that if I dug into Win32api, I could find the secret to how Windows lets one process create and control another, but I find myself strangely without the desire to do so. But if someone tells me it's easy... --------------------------- Here is a sample script that logs in and deals with a demand for a digital certificate. Because I want to be cool, I made a little Domain! Specific! Language! for talking about popups. In the following, it's marked with # !W!O!W! require 'watir' include Watir at_exit do $ie.close end class IE def after(&block) @block = block self end def grab_window(window_title) @window_title = window_title self end def and_send(*keys) dropping = dropping_name_from(@window_title) File.delete(dropping) if File.exist?(dropping) commandline = ["/ruby/bin/ruby", "watcher.rb", "'" + @window_title + "'", dropping] + keys IO.popen(commandline.join(' ')) instance_eval(&@block) if @block until File.exists?(dropping) sleep 1 end end private def dropping_name_from(title) "got-past-" + title.gsub(/\s/, '-') end end $ie = IE.new $ie.goto("https://example.com/cmd/logon") $ie.text_field(:name, "U").set("marick") $ie.text_field(:name, "P").set("not the real one") $ie.after { # !W!O!W! button(:name, "action").click }.grab_window("Choose a digital certificate"). and_send("{Tab}", "{Space}") puts "Th-th-th that's all, folks!" sleep 5 # display final page in all its glory. ==== And here's the watcher script: require 'watir' # Do this in JMock style, just because. class Watcher private_class_method :new def self.after_seeing(title) new(title) end def initialize(title) @autoit = Watir.autoit @title = title end def send(keys) @keys = keys self end def and_leave_dropping_in(dropping_file) @dropping_file = dropping_file do_await_window do_send_keys do_leave_dropping nil end private def do_await_window @autoit.WinWait @title, "" end def do_send_keys @keys.each do | key | sleep 1 # Just to watch it happen. @autoit.Send key end end def do_leave_dropping File.open(@dropping_file, "w") do | io | io.puts("Finished at #{Time.now}.") end end end if $0 == __FILE__ title = ARGV[0] dropping_file = ARGV[1] keys = ARGV[2..-1] $stderr.puts title, dropping_file, keys.inspect; $stderr.flush Watcher.after_seeing(title).send(keys). and_leave_dropping_in(dropping_file) end ----- Brian Marick, independent consultant Mostly on agile methods with a testing slant www.exampler.com, www.exampler.com/blog ----- Brian Marick, independent consultant Mostly on agile methods with a testing slant www.exampler.com, www.exampler.com/blog _______________________________________________ Wtr-general mailing list Wtr-general@rubyforge.org http://rubyforge.org/mailman/listinfo/wtr-general