10

I'm trying to test file download with Watin 2.1.0 against IE9. I used the suggested code from the accepted answer to the question Downloading a file with Watin in IE9, like this:

var downloadHandler = new FileDownloadHandler(fname);
WebBrowser.Current.AddDialogHandler(downloadHandler);
link.ClickNoWait();
downloadHandler.WaitUntilFileDownloadDialogIsHandled(15);
downloadHandler.WaitUntilDownloadCompleted(200);

However, the downloadHandler.WaitUntilFileDownloadDialogIsHandled(15) call times out. What should I do?

Community
  • 1
  • 1
aknuds1
  • 65,625
  • 67
  • 195
  • 317
  • Try waiting longer? For a large file, the File Download dialog may take a while to appear. 15 seconds doesn't look long enough – Jeremy McGee Sep 21 '11 at 13:39
  • @Jeremy McGee The file is very small, and I've verified that the download dialog does appear. I even canceled it manually, and WaitUntilFileDownloadDialogIsHandled still timed out. – aknuds1 Sep 21 '11 at 18:48
  • Try using the DialogHandlerHelper to identify what WATIN thinks the IE9 download dialog window actually is, as it looks to me that IE9's download dialogue does not meat the criteria WATIN is using to find it. – hollystyles Sep 22 '11 at 11:04
  • @HollyStyles I tried DialogHandlerHelper to find any candidate dialog handlers, thanks. None were found though :( – aknuds1 Sep 23 '11 at 08:24
  • 1
    Ugh - I hope someone can find a solution to this, I would really like to be able to automate these download test :( – Tommy Sep 27 '11 at 15:09
  • @Tommy There's a bug in Watin's tracker IIRC. – aknuds1 Sep 27 '11 at 18:47
  • @aknuds1: have you had any luck using System.Windows.Forms.SendKeys? I can get a file to download (click a link, wait 300ms, send Alt+S to the browser) but during scenario cleanup, the browser window hangs for 30 seconds before closing. It is tied to the sendkeys method, but not sure how/what is causing IE to hang up when we use that. – Tommy Sep 27 '11 at 20:09

2 Answers2

21

File download dialog doesn't work in IE9 (Windows7) NetFramework 4.0.

Following code snippet might help you resolve the issue:

First you must add references UIAutomationClient and UIAutomationTypes to your test project.

After In Ie9 Tools -> View Downloads -> Options define path to your save folder.

The next method extends Browser class

public static void DownloadIEFile(this Browser browser)
{
    // see information here (http://msdn.microsoft.com/en-us/library/windows/desktop/ms633515(v=vs.85).aspx)
    Window windowMain = new Window(WatiN.Core.Native.Windows.NativeMethods.GetWindow(browser.hWnd, 5));
   System.Windows.Automation.TreeWalker trw = new  System.Windows.Automation.TreeWalker(System.Windows.Automation.Condition.TrueCondition);
   System.Windows.Automation.AutomationElement mainWindow = trw.GetParent(System.Windows.Automation.AutomationElement.FromHandle(browser.hWnd));

    Window windowDialog = new Window(WatiN.Core.Native.Windows.NativeMethods.GetWindow(windowMain.Hwnd, 5));
    // if doesn't work try to increase sleep interval or write your own waitUntill method
    Thread.Sleep(1000);
    windowDialog.SetActivate();
    System.Windows.Automation.AutomationElementCollection amc = System.Windows.Automation.AutomationElement.FromHandle(windowDialog.Hwnd).FindAll(System.Windows.Automation.TreeScope.Children, System.Windows.Automation.Condition.TrueCondition);

    foreach (System.Windows.Automation.AutomationElement element in amc)
    {
        // You can use "Save ", "Open", ''Cancel', or "Close" to find necessary button Or write your own enum
        if (element.Current.Name.Equals("Save"))
        {
            // if doesn't work try to increase sleep interval or write your own waitUntil method
            // WaitUntilButtonExsist(element,100);
            Thread.Sleep(1000);
            System.Windows.Automation.AutomationPattern[] pats = element.GetSupportedPatterns();
            // replace this foreach if you need 'Save as' with code bellow
            foreach (System.Windows.Automation.AutomationPattern pat in pats)
            {
                // '10000' button click event id 
                if (pat.Id == 10000)
                {
                    System.Windows.Automation.InvokePattern click = (System.Windows.Automation.InvokePattern)element.GetCurrentPattern(pat);
                    click.Invoke();
                }
            }
        }
    }
}

if you want click 'Save As' replace foreach code with this

System.Windows.Automation.AutomationElementCollection bmc =  element.FindAll(System.Windows.Automation.TreeScope.Children,   System.Windows.Automation.Automation.ControlViewCondition);
System.Windows.Automation.InvokePattern click1 =  (System.Windows.Automation.InvokePattern)bmc[0].GetCurrentPattern(System.Windows.Automation.AutomationPattern.LookupById(10000));
click1.Invoke();
Thread.Sleep(10000);

System.Windows.Automation.AutomationElementCollection main =  mainWindow.FindAll(System.Windows.Automation.TreeScope.Children
,System.Windows.Automation.Condition.TrueCondition);
foreach (System.Windows.Automation.AutomationElement el in main)
{
    if (el.Current.LocalizedControlType == "menu")
    {
        // first array element 'Save', second array element 'Save as', third second array element    'Save and open'
        System.Windows.Automation.InvokePattern clickMenu = (System.Windows.Automation.InvokePattern)
                    el.FindAll(System.Windows.Automation.TreeScope.Children,        System.Windows.Automation.Condition.TrueCondition)  [1].GetCurrentPattern(System.Windows.Automation.AutomationPattern.LookupById(10000));
                       clickMenu.Invoke();
        //add ControlSaveDialog(mainWindow, filename) here if needed
        break;

    }
}

Edit: Also if you need to automate the save as dialog specifying a path and clicking save you can do it by adding this code just before break;

private static void ControlSaveDialog(System.Windows.Automation.AutomationElement mainWindow, string path)
{
    //obtain the save as dialog
    var saveAsDialog = mainWindow
                        .FindFirst(TreeScope.Descendants,
                                   new PropertyCondition(AutomationElement.NameProperty, "Save As"));
    //get the file name box
    var saveAsText = saveAsDialog
            .FindFirst(TreeScope.Descendants,
                       new AndCondition(
                           new PropertyCondition(AutomationElement.NameProperty, "File name:"),
                           new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit)))
            .GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
    //fill the filename box 
    saveAsText.SetValue(path);

    Thread.Sleep(1000);
    //find the save button
    var saveButton =
            saveAsDialog.FindFirst(TreeScope.Descendants,
            new AndCondition(
                new PropertyCondition(AutomationElement.NameProperty, "Save"),
                new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button)));
    //invoke the button
    var pattern = saveButton.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
    pattern.Invoke();
}
tomsv
  • 7,207
  • 6
  • 55
  • 88
Boriss Pavlovs
  • 1,441
  • 12
  • 8
  • This is really cool but can the save as dialog be automated to save as a specific file name? I have tried modifying the code but when I look try to find the Save As dialog I am having trouble. – PeteT Apr 24 '12 at 16:37
  • 1
    Worked out automating the save as path and clicking save so added the code to your answer. Hope that is ok. – PeteT Apr 25 '12 at 00:46
  • 2
    Can you post a github gist of the complete solution using Save As? I'm having a hard time getting this to work in IE10. – djbyter Dec 04 '12 at 16:17
8

IE9 no longer uses a dialog window for saving files. Instead, it uses the notification bar to prevent focus from being removed from the web site. See http://msdn.microsoft.com/en-us/ie/ff959805.aspx under "Download Manager" for reference.

Unfortunately, this means that the current FileDownloadHandler in WatiN will not work. It instantiates a "DialogWatcher" class per browser instance that is a basic message pump for any kind of child window. When child windows are encountered, the DialogWatcher checks to see if the window is specifically a dialog (which the notification bar is not). If it is a dialog, it then iterates over the registered IDialogHandler instances calling "CanHandleDialog." Even if the notification bar were a dialog, it is of a different Window Style (http://msdn.microsoft.com/en-us/library/windows/desktop/ms632600(v=vs.85).aspx), which is how WatiN detects the type of dialog.

From what I can see, there is no support yet for detecting the IE 9 notification bar and its prompts in WatiN. Until that support is added, you will not be able to automate downloading files in IE9.

Joe Bako
  • 106
  • 3
  • 1
    Argh, you're probably right although I haven't been able to confirm otherwise. – aknuds1 Sep 23 '11 at 07:39
  • 1
    Using watin 2.1 only it is not possible, but using the method below about the UIAutomation*, it is possible to perform all of the yellow-white-bar commands, including open and save-as. – tomsv Nov 14 '12 at 14:05