从网站下载PDF时,如何在“另存为”对话框中按“确定”

时间:2014-08-27 15:27:31

标签: pdf webdriver

我在C#中使用Selenium WebDriver并且到目前为止已经管理了以下步骤; 转到网页,打开PDF,按下载按钮。

{
[TestFixture]
public class DownloadPDF
{
    private static IWebDriver driver = null;
    private StringBuilder verificationErrors = null;
    private string baseURL;

    [TestFixtureSetUp]
    public void TestSetup()
    {
        driver = new FirefoxDriver();          
        baseURL = ("http://pdfobject.com/");
        driver.Manage().Timeouts().ImplicitlyWait(new TimeSpan(5000));

    }
    [Test]
    public void main()
    {
        driver.Navigate().GoToUrl(baseURL + "/pdf/pdfobject.pdf#view=FitH&pagemode=thumbs&search=pdfobject&toolbar=0&statusbar=0&messages=0&navpanes=1");
        driver.FindElement(By.Id("download")).Click();
    }

}
}

我现在得到一个保存对话框,其中包含2个单选按钮(打开并保存文件)和一个复选框(将来会自动执行此操作)

默认选择的选项是保存文件,因此我想检查'从现在开始自动执行此操作',然后按确定。

我已经看到了一些关于如何实现这一目标的Java示例,但到目前为止,我还没有在C#中找到任何内容。

理想情况下,如果可能的话,我想直接下载到我机器上的文件位置吗?

2 个答案:

答案 0 :(得分:0)

假设您提到的保存对话框不是网页DOM的一部分,Selenium将无法做很多事情。

您可以使用AutoIt来处理这些情况。它是免费的,重量轻,可以处理基本的窗户和控制。通过添加对Interop.AutoItX3Lib.dll的引用,在C#项目中使用它。

以下是我处理AutoIt API的包装类:

namespace QA.AutoIt
{
    using System;
    using AutoItX3Lib;

    public class AutoItWindow
    {
        public static AutoItX3 AutoItDriver;
        public string Title;
        public string Text;

        public AutoItWindow(string windowTitle, string windowText = "")
        {
            AutoItDriver = new AutoItX3();;
            Title = windowTitle;
            Text = windowText;
        }

        public void Activate()
        {
            AutoItDriver.WinActivate(Title, Text);
        }
    }

    public class AutoItElement
    {
        private static AutoItX3 _au3;
        private AutoItWindow _parent;
        private string _controlID;

        public AutoItElement(AutoItWindow parentWindow, string controlID)
        {
            _au3 = AutoItWindow.AutoItDriver;
            _parent = parentWindow;
            _controlID = controlID;
        }

        public void Click(string button = "LEFT")
        {
            // Set the window active
            _parent.Activate();

            // Click on the control
            _au3.ControlClick(_parent.Title, _parent.Text, _controlID, button);
        }

        public void SendText(string textToSend)
        {
            // Set the window active
            _parent.Activate();

            // Send the specified text to the control
            _au3.ControlFocus(_parent.Title, _parent.Text, _controlID);
            _au3.ControlSend(_parent.Title, _parent.Text, _controlID, textToSend);
        }
    }
}

以下是上传文件的示例。与您想要实现的类似。我定义了一个类,该类使用OpenFile方法对对话UI进行建模,以执行所需的操作。使用AutoIt对象间谍工具很容易识别标识窗口及其子控件的字符串。

public class FileOpenWindow : AutoItWindow
{
    #region Child Controls
    public AutoItElement FileNameEdit;
    public AutoItElement OKButton;
    #endregion

    public FileOpenWindow(string title = "Open", string text = "")
        : base(title, text)
    {
        FileNameEdit = new AutoItElement(this, "[CLASS:Edit; INSTANCE:1]");
        OKButton = new AutoItElement(this, "[CLASS:Button; INSTANCE:1]");
    }

    public void OpenFile(string fileName)
    {
        // Wait for the window to appear then activate it
        WaitToAppear(30);
        Activate();

        // Enter in the filename and click OK to start upload
        FileNameEdit.SendText(fileName);
        OKButton.Click();

        // Wait for the window to disappear
        WaitToDisappear(30);
    }
}

答案 1 :(得分:0)

在我的工作中,我通常使用UIAutomation库与桌面应用进行交互。此外,您可以使用一些专为此目的而开发的框架(例如White)。但对我来说,使用winapi,uutoutomation更容易编写我自己的。你可以包装你的对话框并公开它的元素,所以从测试开始就可以很容易地在任何地方使用它。以下代码示例:

[TestFixture]
public class DownloadPDF
{
    private static IWebDriver driver = null;
    private StringBuilder verificationErrors = null;
    private string baseURL;

    [TestFixtureSetUp]
    public void TestSetup()
    {
        driver = new FirefoxDriver();          
        baseURL = ("http://pdfobject.com/");
        driver.Manage().Timeouts().ImplicitlyWait(new TimeSpan(5000));

    }
    [Test]
    public void main()
    {
        driver.Navigate().GoToUrl(baseURL + "/pdf/pdfobject.pdf#view=FitH&pagemode=thumbs&search=pdfobject&toolbar=0&statusbar=0&messages=0&navpanes=1");
        driver.FindElement(By.Id("download")).Click();
        var window = new Window("your window name");
        window.OpenWithBtn.Click();
        window.Save.Click();
    }

}

public class Window
    {
        private readonly string _windowName;
        private AutomationElement _window;

        public Window(string windowName)
        {
            _windowName = windowName;
            _window = GetWindow(_windowName);
        }

        private AutomationElement GetWindow(string windowName)
        {
            return UIAutomationElements.FindDescedantByCondition(AutomationElement.RootElement,
                new PropertyCondition(AutomationElement.NameProperty, windowName));
        }

        private AutomationElement GetElement(string elementName)
        {
            if (_window == null)
                _window = GetWindow(_windowName);
            return UIAutomationElements.FindDescedantByCondition(_window,
                new AndCondition(new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.RadioButton),
                    new PropertyCondition(AutomationElement.NameProperty, elementName)));
        }

        public Button OpenWithBtn
        {
            get
            {
                return new Button(GetElement("Open With..."));
            }
        }

        public Button Save
        {
            get
            {
                return new Button(GetElement("Open With..."));
            }
        }
    }

    public class Button
    {
        private readonly AutomationElement _btnElement;

        public Button(AutomationElement btnElement)
        {
            _btnElement = btnElement;
        }

        public void Click()
        {
            //perform click using winapi or invoke button if 'InvokePattern' available for it
            var invokePattern = _btnElement.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern; 
            invokePattern.Invoke();
        }
    }

public class UIAutomationElements
{
    /// <summary>
    /// Find descedant of specified element by it's index.
    /// </summary>
    /// <param name="element">Main element in which search should be performed.</param>
    /// <param name="condition">Condition by wchich element will be identified. See <see cref="Condition"/>, <see cref="PropertyCondition"/> etc...</param>
    /// <param name="itemIndex">Index of element which should found</param>
    /// <returns>Founded element as <see cref="AutomationElement"/> with specified index</returns>
    public static AutomationElement FindDescedantByCondition(AutomationElement element, Condition condition, int itemIndex)
    {
        var result = element.FindAll(TreeScope.Descendants, condition);

        return result[itemIndex];
    }

    /// <summary>
    /// Find all descedants in the main element.
    /// </summary>
    /// <param name="element">Main element in whick search should be performed.</param>
    /// <param name="condition">Condition by wchich element will be identified. See <see cref="Condition"/>, <see cref="PropertyCondition"/> etc...</param>
    /// <returns><see cref="AutomationElementCollection"/></returns>
    public static AutomationElementCollection FindDescedantsByCondition(AutomationElement element, Condition condition)
    {
        var result = element.FindAll(TreeScope.Descendants, condition);
        return result;
    }

    /// <summary>
    /// Find descedant by specified condition
    /// </summary>
    /// <param name="element">Main element in which search should be performed.</param>
    /// <param name="condition">Condition by wchich element will be identified.
    ///  See <see cref="Condition"/>, <see cref="PropertyCondition"/> etc...</param>
    /// <returns>Element as <see cref="AutomationElement"/></returns>
    public static AutomationElement FindDescedantByCondition(AutomationElement element, Condition condition)
    {
        var result = element.FindFirst(TreeScope.Descendants, condition);

        return result;
    }
}

要执行点击,您可以使用winapi方法。所描述的解决方案的原因here。希望这会有所帮助。

P.S。如果您只需单击“确定”按钮,则无需包装任何内容。只需在其中找到对话框和按钮,然后执行click =)