如何用 Selenium 修复 'IHasInputDevices is obsolete. Use the Actions or ActionsBuilder class to simulate mouse and keyboard input' 警告
How to fix 'IHasInputDevices is obsolete. Use the Actions or ActionsBuilder class to simulate mouse and keyboard input' warning with Selenium
将我们解决方案中的 Selenium NuGet 包升级到版本 3.141.0(Selenium.WebDriver 和 Selenium.Support)后,IHasInputDevices 接口现在有一个警告:
'IHasInputDevices' is obsolete. 'Use the Actions or ActionsBuilder class to simulate mouse and keyboard input.'
我创建了一个名为 LazyWebDriver
的实用程序 class,它实现了 IWebDriver
、IHasInputDevices
和 IActionExecutor
接口。 LazyWebDriver
class 延迟 ChromeDriver
的实例化,直到 IWebDriver
的成员被访问。这允许我们传递一个 IWebDriver 对象并延迟浏览器的出现 window,以防测试在设置阶段失败。
LazyWebDriver 代码class:
public class LazyWebDriver : IWebDriver/*, IHasInputDevices*/, IActionExecutor
{
private System.Func<IWebDriver> createDriver;
private IWebDriver driver;
private IWebDriver Driver
{
get
{
if (driver == null)
driver = createDriver();
return driver;
}
}
public string Url
{
get => Driver.Url;
set => Driver.Url = value;
}
public string Title => Driver.Title;
public string PageSource => Driver.PageSource;
public string CurrentWindowHandle => Driver.CurrentWindowHandle;
public ReadOnlyCollection<string> WindowHandles => Driver.WindowHandles;
public IKeyboard Keyboard => ((IHasInputDevices)Driver).Keyboard;
public IMouse Mouse => ((IHasInputDevices)Driver).Mouse;
public bool IsActionExecutor => ((IActionExecutor)Driver).IsActionExecutor;
public LazyWebDriver(System.Func<IWebDriver> createDriver)
{
this.createDriver = createDriver;
}
public void Close()
{
Driver.Close();
}
public void Dispose()
{
Driver.Dispose();
}
public IWebElement FindElement(By by)
{
return Driver.FindElement(by);
}
public ReadOnlyCollection<IWebElement> FindElements(By by)
{
return Driver.FindElements(by);
}
public IOptions Manage()
{
return Driver.Manage();
}
public INavigation Navigate()
{
return Driver.Navigate();
}
public void Quit()
{
Driver.Quit();
}
public ITargetLocator SwitchTo()
{
return Driver.SwitchTo();
}
public void PerformActions(IList<ActionSequence> actionSequenceList)
{
((IActionExecutor)Driver).PerformActions(actionSequenceList);
}
public void ResetInputState()
{
((IActionExecutor)Driver).ResetInputState();
}
}
警告表明要使用 Actions 或 ActionBuilder class,所以我从 LazyWebDriver class 中删除了 IHasInputDevices 接口,并尝试使用 Actions class:
[TestClass]
public class DeprecatedInterfaceTest
{
[TestMethod]
public void Test()
{
using (var driver = new LazyWebDriver(() => new ChromeDriver()))
{
driver.Navigate().GoToUrl("https://www.whosebug.com");
var link = driver.FindElement(By.CssSelector("a[href='/teams/customers']"));
var actions = new Actions(driver);
actions = actions.MoveToElement(link);
actions = actions.Click(link);
actions.Perform();
}
}
}
测试失败,出现以下错误消息:
Test method DeprecatedInterfaceTest.Test threw exception:
System.ArgumentException: The IWebDriver object must implement or wrap a driver that implements IHasInputDevices.
Parameter name: driver
测试在这一行失败:
var actions = new Actions(driver);
我在网上进行了一些搜索,但没有找到消除 IHasInputDevices 接口并使用过时警告中指示的操作 class 的方法。它还显示 ActionBuilder class 用于排队一堆 Actions 对象。
如何删除 IHasInputDevices 接口并仍然使用 Actions class?
至少在 3.14 中你不能删除 IHasInputDevices 接口
参考这个 selenium-3.141.59/dotnet/src/webdriver/Interactions/Actions.cs#L68 Its checking for IHasInputDevices . Even RemoteWebdriver 在 3.14 实现 IHasInputDevices 所以你的 LazyWebDriver 必须实现它。
IHasInputDevices inputDevicesDriver = GetDriverAs<IHasInputDevices>(driver);
这将检查并抛出异常
public Actions(IWebDriver driver)
{
//this.driver = driver;
IHasInputDevices inputDevicesDriver = GetDriverAs<IHasInputDevices>(driver);
if (inputDevicesDriver == null)
{
throw new ArgumentException("The IWebDriver object must implement or wrap a driver that implements IHasInputDevices.", "driver");
}
IActionExecutor actionExecutor = GetDriverAs<IActionExecutor>(driver);
if (actionExecutor == null)
{
throw new ArgumentException("The IWebDriver object must implement or wrap a driver that implements IActionExecutor.", "driver");
}
this.keyboard = inputDevicesDriver.Keyboard;
this.mouse = inputDevicesDriver.Mouse;
this.actionExecutor = actionExecutor;
}
与 Selenium 4 一样。 IHasInputDevices 已删除。 ChangeLog
Removed IHasInputDevices and IHasTouchScreen and implementations. The Mouse,
Keyboard, and TouchScreen implementations in the .NET bindings were never
intended to be used by user code. Instead, users are expected to use the
Actions and TouchActions classes or the ActionBuilder class to create
complex interactions with pages being automated. This change reinforces that
behavior, making it explicit.
如果您在 Selenium 4 中实现 LazyWebdriver,那么您将不会遇到此问题,因为 IHasInputDevices 已被删除并且 Actions class 仅检查 IActionExecutor。参考 Actions.cs selenium-4.0.0-alpha-6
public Actions(IWebDriver driver)
{
IActionExecutor actionExecutor = GetDriverAs<IActionExecutor>(driver);
if (actionExecutor == null)
{
throw new ArgumentException("The IWebDriver object must implement or wrap a driver that implements IActionExecutor.", "driver");
}
this.actionExecutor = actionExecutor;
}
将我们解决方案中的 Selenium NuGet 包升级到版本 3.141.0(Selenium.WebDriver 和 Selenium.Support)后,IHasInputDevices 接口现在有一个警告:
'IHasInputDevices' is obsolete. 'Use the Actions or ActionsBuilder class to simulate mouse and keyboard input.'
我创建了一个名为 LazyWebDriver
的实用程序 class,它实现了 IWebDriver
、IHasInputDevices
和 IActionExecutor
接口。 LazyWebDriver
class 延迟 ChromeDriver
的实例化,直到 IWebDriver
的成员被访问。这允许我们传递一个 IWebDriver 对象并延迟浏览器的出现 window,以防测试在设置阶段失败。
LazyWebDriver 代码class:
public class LazyWebDriver : IWebDriver/*, IHasInputDevices*/, IActionExecutor
{
private System.Func<IWebDriver> createDriver;
private IWebDriver driver;
private IWebDriver Driver
{
get
{
if (driver == null)
driver = createDriver();
return driver;
}
}
public string Url
{
get => Driver.Url;
set => Driver.Url = value;
}
public string Title => Driver.Title;
public string PageSource => Driver.PageSource;
public string CurrentWindowHandle => Driver.CurrentWindowHandle;
public ReadOnlyCollection<string> WindowHandles => Driver.WindowHandles;
public IKeyboard Keyboard => ((IHasInputDevices)Driver).Keyboard;
public IMouse Mouse => ((IHasInputDevices)Driver).Mouse;
public bool IsActionExecutor => ((IActionExecutor)Driver).IsActionExecutor;
public LazyWebDriver(System.Func<IWebDriver> createDriver)
{
this.createDriver = createDriver;
}
public void Close()
{
Driver.Close();
}
public void Dispose()
{
Driver.Dispose();
}
public IWebElement FindElement(By by)
{
return Driver.FindElement(by);
}
public ReadOnlyCollection<IWebElement> FindElements(By by)
{
return Driver.FindElements(by);
}
public IOptions Manage()
{
return Driver.Manage();
}
public INavigation Navigate()
{
return Driver.Navigate();
}
public void Quit()
{
Driver.Quit();
}
public ITargetLocator SwitchTo()
{
return Driver.SwitchTo();
}
public void PerformActions(IList<ActionSequence> actionSequenceList)
{
((IActionExecutor)Driver).PerformActions(actionSequenceList);
}
public void ResetInputState()
{
((IActionExecutor)Driver).ResetInputState();
}
}
警告表明要使用 Actions 或 ActionBuilder class,所以我从 LazyWebDriver class 中删除了 IHasInputDevices 接口,并尝试使用 Actions class:
[TestClass]
public class DeprecatedInterfaceTest
{
[TestMethod]
public void Test()
{
using (var driver = new LazyWebDriver(() => new ChromeDriver()))
{
driver.Navigate().GoToUrl("https://www.whosebug.com");
var link = driver.FindElement(By.CssSelector("a[href='/teams/customers']"));
var actions = new Actions(driver);
actions = actions.MoveToElement(link);
actions = actions.Click(link);
actions.Perform();
}
}
}
测试失败,出现以下错误消息:
Test method DeprecatedInterfaceTest.Test threw exception:
System.ArgumentException: The IWebDriver object must implement or wrap a driver that implements IHasInputDevices.
Parameter name: driver
测试在这一行失败:
var actions = new Actions(driver);
我在网上进行了一些搜索,但没有找到消除 IHasInputDevices 接口并使用过时警告中指示的操作 class 的方法。它还显示 ActionBuilder class 用于排队一堆 Actions 对象。
如何删除 IHasInputDevices 接口并仍然使用 Actions class?
至少在 3.14 中你不能删除 IHasInputDevices 接口
参考这个 selenium-3.141.59/dotnet/src/webdriver/Interactions/Actions.cs#L68 Its checking for IHasInputDevices . Even RemoteWebdriver 在 3.14 实现 IHasInputDevices 所以你的 LazyWebDriver 必须实现它。
IHasInputDevices inputDevicesDriver = GetDriverAs<IHasInputDevices>(driver);
这将检查并抛出异常
public Actions(IWebDriver driver)
{
//this.driver = driver;
IHasInputDevices inputDevicesDriver = GetDriverAs<IHasInputDevices>(driver);
if (inputDevicesDriver == null)
{
throw new ArgumentException("The IWebDriver object must implement or wrap a driver that implements IHasInputDevices.", "driver");
}
IActionExecutor actionExecutor = GetDriverAs<IActionExecutor>(driver);
if (actionExecutor == null)
{
throw new ArgumentException("The IWebDriver object must implement or wrap a driver that implements IActionExecutor.", "driver");
}
this.keyboard = inputDevicesDriver.Keyboard;
this.mouse = inputDevicesDriver.Mouse;
this.actionExecutor = actionExecutor;
}
与 Selenium 4 一样。 IHasInputDevices 已删除。 ChangeLog
Removed IHasInputDevices and IHasTouchScreen and implementations. The Mouse,
Keyboard, and TouchScreen implementations in the .NET bindings were never
intended to be used by user code. Instead, users are expected to use the
Actions and TouchActions classes or the ActionBuilder class to create
complex interactions with pages being automated. This change reinforces that
behavior, making it explicit.
如果您在 Selenium 4 中实现 LazyWebdriver,那么您将不会遇到此问题,因为 IHasInputDevices 已被删除并且 Actions class 仅检查 IActionExecutor。参考 Actions.cs selenium-4.0.0-alpha-6
public Actions(IWebDriver driver)
{
IActionExecutor actionExecutor = GetDriverAs<IActionExecutor>(driver);
if (actionExecutor == null)
{
throw new ArgumentException("The IWebDriver object must implement or wrap a driver that implements IActionExecutor.", "driver");
}
this.actionExecutor = actionExecutor;
}