I'm having an issue with automating the process of downloading a file from a website. The website has a Java button, that when clicked, triggers the download of an Excel file. I'm using the most recent build of Watin (v2.1).
I've managed to get Watin to log into the website, navigate to the appropriate page, change parameters on the page, and click the button to start the download.
However, when the download has completed, the IE9 download box appears, and nothing happens, until Watin timesout.
I'd appreciate any suggestions as I can't see any way of downloading a file, or getting it to save the file. Even if it passed 'Alt+S' to the page, that would save it. I've tried running it through WatinTestRecorder and that doesn't prompt for saving.
using (var browser = new IE(sLogin))
{
browser.AddDialogHandler(new OKDialogHandler());
browser.AddDialogHandler(new DialogHandlerHelper());
browser.AddDialogHandler(new ConfirmDialogHandler());
browser.AddDialogHandler(new ReturnDialogHandlerIe9());
browser.TextField(Find.ByName("txtUserID")).TypeText("username");
browser.TextField(Find.ByName("txtPassword")).TypeText("password");
browser.Button(Find.ByName("btnLogin")).Click();
browser.WaitForComplete();
browser.GoTo(targetUri);
browser.SelectList("ctl00_phFormContent_ucOptionParam0_lst").SelectByValue("4");
browser.Button(Find.ByName("ctl00$phFormButtonBar$btnRun")).Click();
browser.WaitForComplete();
//Some code to download the file here!
}
This should be supported since version 1.1.0.4000. The release notes for that version aren't online anymore (http://watin.org/documentation/), but I found it in Googles cache (http://svn6.assembla.com/svn/ci-samples/dotnet/watir/website/releasenotes-1-1-0-4000.html)
It should be something like:
using(IE ie = new IE(someUrlToGoTo))
{
FileDownloadHandler fileDownloadHandler = new FileDownloadHandler(fullFileName);
ie.AddDialogHandler(fileDownloadHandler);
ie.Link("startDownloadLinkId").Click();
fileDownloadHandler.WaitUntilFileDownloadDialogIsHandled(15);
fileDownloadHandler.WaitUntilDownloadCompleted(200);
}
EDIT: After the comments below, this answer was accepted. So I'm assuming the following code works (which is taken from the link to SourceForge in my last comment, notice the ClickNoWait):
using(IE ie = new IE(someUrlToGoTo))
{
FileDownloadHandler fileDownloadHandler = new FileDownloadHandler(fullFileName);
ie.AddDialogHandler(fileDownloadHandler);
ie.Link("startDownloadLinkId").ClickNoWait();
fileDownloadHandler.WaitUntilFileDownloadDialogIsHandled(15);
fileDownloadHandler.WaitUntilDownloadCompleted(200);
}
The accepted answer did not work for me because IE 9 pops up a "Notification" you have to navigate before you can get to the actual Save As dialog (and WatiN cannot handle notifications automatically). I followed Borris Pavlov's link which did a good job showing the way. I cleaned up the code a bit that was posted there and this was the resulting file:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WatiN.Core;
using WatiN.Core.Native.Windows;
using System.Threading;
using System.Windows.Automation;
namespace MyProject
{
public static class BrowserExtensionMethods
{
public static void DownloadIeFile(this IE browser,string saveAsFilename=null)
{
// see information here (http://msdn.microsoft.com/en-us/library/windows/desktop/ms633515(v=vs.85).aspx)
Window windowMain = new Window(NativeMethods.GetWindow(browser.hWnd, 5));
TreeWalker dialogElementTreeWalker = new TreeWalker(Condition.TrueCondition);
AutomationElement mainWindow = dialogElementTreeWalker.GetParent(AutomationElement.FromHandle(browser.hWnd));
Window windowDialog = new Window(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();
AutomationElementCollection dialogElements = AutomationElement.FromHandle(windowDialog.Hwnd).FindAll(TreeScope.Children, Condition.TrueCondition);
if (string.IsNullOrEmpty(saveAsFilename))
{
ClickSave(dialogElements);
}
else
{
ClickSaveAs(mainWindow, dialogElements,saveAsFilename);
}
}
private static void ClickSaveAs(AutomationElement mainWindow, AutomationElementCollection dialogElements,string filename)
{
foreach (AutomationElement element in dialogElements)
{
if (element.Current.Name.Equals("Save"))
{
AutomationElementCollection dialogSubElements = element.FindAll(TreeScope.Children, Automation.ControlViewCondition);
InvokePattern clickPatternForSaveDropdown = (InvokePattern)dialogSubElements[0].GetCurrentPattern(AutomationPattern.LookupById(10000));
clickPatternForSaveDropdown.Invoke();
Thread.Sleep(3000);
AutomationElementCollection dialogElementsInMainWindow = mainWindow.FindAll(TreeScope.Children, Condition.TrueCondition);
foreach (AutomationElement currentMainWindowDialogElement in dialogElementsInMainWindow)
{
if (currentMainWindowDialogElement.Current.LocalizedControlType == "menu")
{
// first array element 'Save', second array element 'Save as', third second array element 'Save and open'
InvokePattern clickMenu = (InvokePattern)currentMainWindowDialogElement.FindAll(TreeScope.Children, Condition.TrueCondition)[1].GetCurrentPattern(AutomationPattern.LookupById(10000));
clickMenu.Invoke();
Thread.Sleep(5000);
ControlSaveDialog(mainWindow, filename);
break;
}
}
}
}
}
private static void ClickSave(AutomationElementCollection dialogElements)
{
foreach (AutomationElement element in dialogElements)
{
// 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);
AutomationPattern[] automationPatterns = element.GetSupportedPatterns();
// replace this foreach if you need 'Save as' with code bellow
foreach (AutomationPattern currentPattern in automationPatterns)
{
// '10000' button click event id
if (currentPattern.Id == 10000)
{
InvokePattern click = (InvokePattern)element.GetCurrentPattern(currentPattern);
click.Invoke();
}
}
}
}
}
private static void ControlSaveDialog(AutomationElement mainWindow, string path)
{
//obtain the save as dialog
//*** must disable throwing of the NonComVisibleBaseClass "exception" for this to work in debug mode:
// 1. Navigate to Debug->Exceptions...
// 2. Expand "Managed Debugging Assistants"
// 3. Uncheck the NonComVisibleBaseClass Thrown option.
// 4. Click [Ok]
//***copied from http://social.msdn.microsoft.com/Forums/en-US/27c3bae8-41fe-4db4-8022-e27d333f714e/noncomvisiblebaseclass-was-detected?forum=Vsexpressvb
var saveAsDialog = mainWindow.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "Save As"));
//var saveAsDialog = mainWindow.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "[#] Save As [#]")); //needed if using sandboxie
//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();
}
}
}
See the comment in the ControlSaveDialog method for info on how to make this work as a debug build (VS settings).
I actually only tested the "Save As" operation so I hope the other works (it seems that the original poster added the "Save As" as an afterthought so my guess is that he tested the "Save" operation more thoroughly).
To call this you can use some code like:
Link lastMp4Link = mp4Links[mp4Links.Count - 1]; //mp4Links is a WatiN.Core.LinkCollection
lastMp4Link.Click();
browser.DownloadIeFile(string.Format(@"c:\temp\myFile.blah")); //"browser" is a WatiN.Core.IE object
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With