Как исправить «IHasInputDevices устарел. Используйте класс Actions или ActionsBuilder для имитации предупреждения ввода с помощью мыши и клавиатуры с помощью Selenium.

После обновления пакетов Selenium NuGet в нашем решении до версии 3.141.0 (и Selenium.WebDriver, и Selenium.Support) интерфейс IHasInputDevices теперь имеет предупреждение:

IHasInputDevices устарел. «Используйте класс Actions или ActionsBuilder для имитации ввода с помощью мыши и клавиатуры».

Снимок экрана с предупреждением об устаревании в Visual Studio

Я создал служебный класс LazyWebDriver, который реализует интерфейсы IWebDriver, IHasInputDevices и IActionExecutor. Класс LazyWebDriver откладывает создание экземпляра ChromeDriver до тех пор, пока не будет получен доступ к члену IWebDriver. Это позволяет нам передавать объект IWebDriver и задерживать появление окна браузера в случае сбоя теста на этапе установки.

Код для класса LazyWebDriver:

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, поэтому я удалил интерфейс IHasInputDevices из класса LazyWebDriver и попытался использовать класс Actions:

[TestClass]
public class DeprecatedInterfaceTest
{
    [TestMethod]
    public void Test()
    {
        using (var driver = new LazyWebDriver(() => new ChromeDriver()))
        {
            driver.Navigate().GoToUrl("https://www.stackoverflow.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();
        }
    }
}

Тест завершился неудачно со следующим сообщением об ошибке:

Метод тестирования DeprecatedInterfaceTest.Test вызвал исключение:
System.ArgumentException: объект IWebDriver должен реализовать или обернуть драйвер, который реализует IHasInputDevices.
Имя параметра: driver

Тест не проходит в этой строке:

var actions = new Actions(driver);

Я провел поиск в Интернете и не нашел способа исключить интерфейс IHasInputDevices и использовать класс Actions, как указано в устаревшем предупреждении. Также кажется, что класс ActionBuilder используется для постановки в очередь множества объектов Actions.

Как удалить интерфейс IHasInputDevices и по-прежнему использовать класс Actions?


person Greg Burghardt    schedule 24.07.2020    source источник


Ответы (1)


По крайней мере в 3.14 нельзя убрать интерфейс IHasInputDevices

Обратитесь к этому selenium- 3.141.59/dotnet/src/webdriver/Interactions/Actions.cs#L68 Проверяет IHasInputDevices . Даже 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;
        }

Как в Селене 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.

Если вы реализуете LazyWebdriver в Selenium 4, у вас не будет этой проблемы, поскольку IHasInputDevices удален, а класс Actions проверяет только IActionExecutor . См. Actions.cs селен-4.0.0-альфа-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;
}
person Rahul L    schedule 30.07.2020
comment
Хорошо. Так что ничего особенного. Просто обновитесь, когда выйдет 4.0, и удалите глупый интерфейс из моего класса LazyWebDriver. Наконец, легко решить проблему. Спасибо! - person Greg Burghardt; 30.07.2020