Search code examples
ruby-on-railsselenium-chromedrivercucumbercapybara

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


I updated my Chrome and Chromedriver to the latest version yesterday, and since then I get the following error messages when running my Cucumber features:

....
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>
      .....

I try to fill a text field with Capybara's fill_in method. While debugging I noticed that Capybara has problems especially with the symbols @ and \. Every other character can be written into the text field without any problems.

The code that triggers the error looks like this

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 contains a string like "[email protected]".

I work with Rails 6.1.3.1, Cucumber 5.3.0, Chromedriver 98.0.4758.48, capybara 3.35.3

The error only occurs on features that are tagged with @javascript

Do you have any ideas what causes this error or how to fix it?


Solution

  • For now the easiest is to pin to an earlier version of the chrome driver, so add this to your capybara config

    In ruby

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

    Hopefully this issue will be addressed in future chromedriver releases, it has been raised and is discussed here

    I also played around with overriding the fill_in method.

    This is less than ideal, and actually OS dependent, so please provide better solution or update this answer. I will try to update as my research progresses.

    
    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