Selenium-chromedriver:无法从不可键入的键构造 KeyEvent

Selenium-chromedriver: Cannot construct KeyEvent from non-typeable key

我昨天将我的 Chrome 和 Chrome 驱动程序更新到最新版本,从那时起,我在 运行 我的 Cucumber 功能时收到以下错误消息:

....
unknown error: Cannot construct KeyEvent from non-typeable key
        (Session info: chrome=98.0.4758.80) (Selenium::WebDriver::Error::UnknownError)
      #0 0x55e9ce6a4093 <unknown>
      #1 0x55e9ce16a648 <unknown>
      #2 0x55e9ce1a9866 <unknown>
      #3 0x55e9ce1cbd29 <unknown>
      .....

我尝试使用 Capybara 的 fill_in 方法填充文本字段。在调试时我注意到 Capybara 有问题,尤其是符号 @\。所有其他字符都可以毫无问题地写入文本字段。

触发错误的代码如下所示

def sign_in(user)
  visit new_sign_in_path
  fill_in 'Email', with: user.email
  fill_in 'Password', with: user.password
  click_button 'Sign in'
end

user.email 包含类似 "example1@mail.com".

的字符串

我使用 Rails 6.1.3.1,Cucumber 5.3.0,Chrome驱动程序 98.0.4758.48,水豚 3.35.3

错误仅发生在标记为 @javascript

的要素上

您知道导致此错误的原因或解决方法吗?

新版本的 ChromeDriver 似乎发生了一些变化,无法再使用 send_keys 方法直接发送一些特殊字符。

在此 link 中,您将看到它是如何解决的(在 C# 中)-->

关于 python 的实现,请查看 --> https://www.geeksforgeeks.org/special-keys-in-selenium-python/

具体来说,我的实现是(使用 MAC):

driver.find_element('.email-input', 'user@mail.com')

现在我不得不更改它:

from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains

emailParts = 'user@mail.com'.split('@')
emailElement = driver.find_element('.email-input')

emailElement.send_keys(emailParts[0])
action = ActionChains(driver)
action.key_down(Keys.ALT).send_keys('2').key_up(Keys.ALT).perform()
emailElement.send_keys(emailParts[1])

目前最简单的方法是 固定到早期版本的 chrome 驱动程序,因此将其添加到您的水豚配置中

在ruby

# /test/support/system/capybara_config.rb
require 'webdrivers/chromedriver'
Webdrivers::Chromedriver.required_version = '97.0.4692.71'

希望这个问题将在未来的 chrome 驱动程序版本中得到解决,它有 been raised and is discussed here

我还尝试重写 fill_in 方法。

这不太理想,实际上 OS 依赖,所以请提供更好的解决方案或更新此答案。随着我研究的进展,我会尽量更新。


class ApplicationSystemTestCase < ActionDispatch::SystemTestCase

  # overriding the `fill_in` helper for filling in strings with an `@` symbol
  def fill_in(locator = nil, with:, currently_with: nil, fill_options: {}, **find_options)
    return super unless with.include? "@"

    find_options[:with] = currently_with if currently_with
    find_options[:allow_self] = true if locator.nil?
    element = find(:fillable_field, locator, **find_options)
    email_front, email_back = with.split("@")

    element.send_keys(email_front)
    page.driver.browser.action
        .key_down(Selenium::WebDriver::Keys[:alt])
        .send_keys('g')
        .key_up(Selenium::WebDriver::Keys[:alt])
        .perform
    element.send_keys(email_back)
  end
end

我有同样的问题。我为 Selenium java 解决了它,例如:

 String arroba = Keys.chord(Keys.ALT, "2");

 String[] mailSplit = mail.split("@");

 userInput.sendKeys(mailSplit[0]);

 userInput.sendKeys(arroba);
 userInput.sendKeys(Keys.BACK_SPACE);

 userInput.sendKeys(mailSplit[1]);

我遇到了与Python相同的问题,似乎仅使用 ActionChains 可以轻松解决问题。

from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By

def safe_send_keys(
    driver,
    input_selector: str,
    input_text: str,
    selector_type = By.CSS_SELECTOR
):
    driver.find_element(selector_type, input_selector).click()
    action = ActionChains(driver)
    action.send_keys(input_text)
    action.perform()

# Example
driver = webdriver.Chrome()
# ... Go to your web page
email = "email_with_at@email.com"
selector = "input_selector"
safe_send_keys(driver, selector, email)

更新 Google Chrome 从上一版本:97.0.4692.99-1 到最新版本:98.0。 4758.80-1 也影响我的代码。 我正在使用 Python,但我无法发送更多的字符如 @、^。 目前,我只是简单地降级GoogleChrome的版本。 它影响了这样的结构: self.driver.find_element_by_id('id_password').send_keys(密码),例如密码包含 ^.

Link 到 linux 机器上 chrome 版本的简单降级: https://makandracards.com/makandra/486433-how-to-downgrade-google-chrome-in-ubuntu

就用JavascriptExecutor,例如:

 JavascriptExecutor jse = (JavascriptExecutor) getDriver();
 jse.executeScript("arguments[0].setAttribute('value', arguments[1])", googleEmailWebElement, email);

今天我的 co-worker 遇到了同样的问题。

对我们有用的是从 Chrome 设置中删除任何语言,但英语(我也在使用波兰语,似乎它不会导致问题)。

机器:装有 macOS Monterey 12.1 的 MacBook Pro;测试框架:Java 11/Selenium

Chrome v.98 - Language settings

此答案适用于 Java 和 WebDriverManager 用户。

您可以在开始前像这样指定 chrome 驱动程序版本 chrome。

WebDriverManager.chromedriver().browserVersion("97").setup();

您可以解决此问题。

更新

This ChromeDriver bug has fixed

希望这是一个临时问题,会在以后的版本中解决 https://github.com/SeleniumHQ/selenium/issues/10318

使用JS填充字段的测试宏解决了我对

等基本场景的需求(Ruby)
fill_in :user_email, with: user.email

测试宏:

def fill_in_chrome98_tmp_fix(locator, with:)
  element = find(:fillable_field, locator)
  dom_id = element.native.dom_attribute("id")
  raise "No DOM ID" if dom_id.blank?
  page.execute_script("document.getElementById('#{dom_id}').value = '#{with}'")
end

这个问题也影响了我。此答案适用于 Python。这就是我目前在 Django 中设置硒测试的方式。我的 chromium 浏览器是 snap 版本 98.0.4758.80.

@classmethod
def setUpClass(cls):
    super().setUpClass()

    options = webdriver.ChromeOptions()
    options.add_argument('--no-sandbox')  # Must be the very first option
    options.add_argument('--headless')
    options.add_argument('--disable-gpu')
    options.add_argument('--disable-software-rasterizer')

    options.add_argument('--disable-dev-shm-usage')
    options.add_argument("--remote-debugging-port=9222")
    options.add_argument("--no-default-browser-check")
    options.add_argument("--no-first-run")
    options.add_argument("--disable-default-apps")

    s = Service(
        ChromeDriverManager(
            # version='98.0.4758.80',
            # version='98.0.4758.48',
            version='97.0.4692.71',
            log_level=logging.WARNING,
            chrome_type=ChromeType.CHROMIUM).install())

    cls.selenium = webdriver.Chrome(
        service=s,
        options=options)
    cls.selenium.implicitly_wait(1)

我在 python 中遇到了同样的错误。如果 Google chrome 自动更新到版本 98,请不要将您的 chrome 驱动程序也更新到 98,use 97 instead。这解决了我的问题。

我在 Java 中使用 Selenium。在 Google Chrome 更新之前,我一直在自动化登录功能,没有任何问题。更新后,我也开始遇到同样的错误。我刚刚将键盘语言更改为“美国”,问题就解决了。

更新:最近(mid-February)我的 Chrome 驱动程序停止给出同样的错误。我不确定是否有修复,因为自从我开始遇到问题以来我没有看到新版本,但我的 Java/Selenium 自动化代码 运行 没有任何错误,无论键盘语言如何,发送字符如'@'。因此,无需再将键盘语言切换为“美国”。