Thursday, September 23, 2010

Automatically click Yes on Internet Explorer Security Alert in Python for automated testing (with Selenium)

Trying to run Selenium RC tests for a secure test website, and kept getting an "alert" from Internet Explorer 6 that there's a problem with the certificate. After searching for answers, I couldn't find a solution to force Internet Explorer 6 to ignore/accept the cert, despite adding it to "trusted sites", and the certificate to "Trusted" stores. In my case, the alert mentions the company name does not match (so it seems it will never accept it).

So, the only workaround I could think of was to automatically click the Yes button (or maybe send alt+y). Below is the python code that seems to do the trick for me:

import win32gui
import win32api


def ie_secalert_yes(maxtry=10):     
    """Left click YES button if the IE Security Alert dialog is found.
    Put this is in a thread, lest it be blocked from ever finding the alert.
   
    Keyword arguments:
    maxtry -- Give up looking for dialog after this many attempts (default 10)
   
    Note:
    (hdlg) FindWindow did not seem to work with class = "Dialog", but 32770
    does.
   
    """
   
    hdlg = 0
    hwnd = 0
    curtry = 0
   
    while curtry < maxtry: 
        hdlg = win32gui.FindWindow(32770, "Security Alert")
        if hdlg == 0:
            curtry += 1
            time.sleep(0.2)
        else:
            curtry=maxtry

     if hdlg > 0:
        hwnd = win32gui.FindWindowEx(hdlg,0,"Button", "&Yes")
        if hwnd > 0:
            win32api.PostMessage(hwnd, 0x0201, 0, 0) #WM_LBUTTONDOWN
            win32api.PostMessage(hwnd, 0x0202, 0, 0) #WM_LBUTTONUP
 
 

You could return hdlg or hwnd if you wanted, they'll be > 0 if the dialog was found. The above also works fine when there is no alert dialog too, in case there's any concern. This could easily be adapted/extended to handle any other window outside of selenium's control.

You should put the above in a thread (I used a timer), then init the timer before selenium, but run it after selenium.start, an example

t = threading.Timer(3.0, ie_secalert_yes)
    self.selenium = selenium("localhost", 4444, "*iexplore", URL) 
    self.selenium.start()
    t.start()
 
 


Caveats: Only tested in Windows XP, Selenium RC 2, and Python 2.6.5, Internet Explorer 6.