我在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#中找到任何内容。
理想情况下,如果可能的话,我想直接下载到我机器上的文件位置吗?
答案 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 =)