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 "example1#mail.com".
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?
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
It seems something has changed in the new version of ChromeDriver and it is no longer possible to send some special chars directly using send_keys method.
In this link you will see how it is solved (in C#) --> Selenium - SendKeys("#") write an "à"
And regarding python implementation, check this out --> https://www.geeksforgeeks.org/special-keys-in-selenium-python/
Specifically, my implementation was (using MAC):
driver.find_element('.email-input', 'user#mail.com')
Now I had to change it by:
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])
I had the same problem with Python, and it seems that using only ActionChains solves the problem in an easy way.
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)
This answer is for Java and WebDriverManager users.
You can specify chrome driver version like this before start chrome.
WebDriverManager.chromedriver().browserVersion("97").setup();
You can work around this problem.
Update
This ChromeDriver bug has fixed
Just use JavascriptExecutor, for example:
JavascriptExecutor jse = (JavascriptExecutor) getDriver();
jse.executeScript("arguments[0].setAttribute('value', arguments[1])", googleEmailWebElement, email);
We had the same issue with my co-worker today.
What worked for us was removing any language from the Chrome settings, but the English (I'm using the Polish language as well and it seems like it's not causing the issue).
Machine: MacBook Pro with macOS Monterey 12.1; Test Framework: Java 11/Selenium
Chrome v.98 - Language settings
I was getting the same error for python. If Google chrome automatically updated to version 98 don't update your chromedriver to 98 also, use 97 instead. This solved my issue.
I am using Selenium with Java. I have been automating login functions without any problem until the Google Chrome update. After the update, I started getting the same error as well. I just changed my keyboard language to "US" and the problem is solved.
Update: Recently (mid-February) my ChromeDriver stopped giving the same error. I am not sure if there has been a fix as I didn't see a new release since I started having problems but my Java/Selenium automation codes run without any error regardless of the keyboard language and send characters like '#'. So, no need to switch the keyboard language to "US" anymore.
I have same problem. I solved it for Selenium java like:
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]);
This is hopefully a temporary problem that will be solved in a later release
https://github.com/SeleniumHQ/selenium/issues/10318
A test macro using JS to fill in the field solved my needs (Ruby) for basic scenarios like
fill_in :user_email, with: user.email
Test macro:
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
This issue affected me as well. This answer is for Python. This is how I currently set up my selenium tests in django. My chromium browser is snap version 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)
Update of Google Chrome from the previous Version: 97.0.4692.99-1 to the newest one Version: 98.0.4758.80-1 also affect my code.
I am using Python and I couldn't send any more characters as #, ^.
For now, I simply downgrade the version of Google Chrome.
It affected on such a structure:
self.driver.find_element_by_id('id_password').send_keys(password), where e.g. password contains ^.
Link to a simple downgrade of chrome version on linux machines:
https://makandracards.com/makandra/486433-how-to-downgrade-google-chrome-in-ubuntu
Specs: Rails 5.2, Ruby 2.5.1, Yarn 1.91.1, React-Rails 2.6.0, selenium-webdriver 3.14, chromedriver 77, capybara gem 3.29 , Ubuntu 18.04
Issue: I created a questionnaire using react components in a Rails app which works when run in development mode. I can click the yes or no button then a callback function renders the new question text. However my selenium integration tests don't pick this up. The page object continues to have the same text for the first question so I receive an error like this
Failure/Error: expect(question.text).to include('last question')
expected "first question" to include "last question"
The test itself looks like this in features/questionnaire.rb
RSpec.feature "Onboarding Questionnaire", type: :feature, js:true do
(...)
it...
question = find('h3.question')
expect(question.text).to include('first question')
yes = find('#yes')
yes.click
sleep 5
question = find('h3.question')
expect(question.text).to include('last question')
The problem arises after yes.click. I thought at first my animations were causing the issue, but I removed those and it is just using setState in my callback function.
Here is my react callback function
saveAnswer(e) {
questionnaire = this
++questionnaire.state.page
questionnaire.setState({page: questionnaire.state.page})
}
Here is my driver config
Capybara.javascript_driver = :selenium_chrome_headless
Now using sleep works as desired. Here are the changes I made.
1) I removed the deprecated gem chromedriver-helper and replaced it with webdrivers
2) Added require 'webdrivers' to the rails_helper.rb file.
3) Found error in my react code (which wasn't showing up in development or being logged in chrome webdriver) of questionnaire = this which I changed to var questionnaire = this.
Integration tests now pass fine using selenium_chrome_headless
I test following assumption And I click on the text "2018/2019" within ".year" with capybara/headless_chrome and constantly get the error
element not visible
(Session info: headless chrome=67.0.3396.87)
(Driver info: chromedriver=2.40.565386 (45a059dc425e08165f9a10324bd1380cc13ca363),platform=Mac OS X 10.13.5 x86_64) (Selenium::WebDriver::Error::ElementNotVisibleError)
I've already tried to adjust the window size, as suggested here. But it didn't work.
My step definition:
When(/^(?:|I )click on the text "([^"]*)"(?: within "([^"]*)")?$/) do |link, selector|
begin
page.find(:css, selector).click
end
end
The element is actually visible and found by Capybara
[1] pry(#<Cucumber::Rails::World>)> page.find(:css, ".year")
=> #<Capybara::Node::Element tag="a" path="/html/body/div[2]/div[2]/section/div[2]/div/div[1]/div[1]/div[2]/div/div[2]/ul/li/a">
But click fails
[2] pry(#<Cucumber::Rails::World>)> page.find(:css, ".year").click
Selenium::WebDriver::Error::ElementNotVisibleError: element not visible
Why doesn't click work here?
EDIT:
The HAML of the link is
%ul.facet_values
- unselected.each do |facet_value|
%li.filtered{data: {hayf: {text: facet_value.name.downcase}}}
= link_to facet_value.path, title: facet_value.name, class: 'year' do
=truncate("#{facet_value.name}", length: 24)
- if facet.has_counts?
%span.small="(#{facet_value.count})"
I tried headless testing with Poltergeist and got Poltergeist detected another element with CSS selector 'html body header div.container-fluid' at this position which was solved with .trigger('click') and the test passed.
Since this doesn't work in non-headless Chrome or Poltergeist, then the simplest answer is that the element isn't actually visible. Firstly remove the Capybara.ignore_hidden_elements = false setting since that makes no sense when testing an app, and will screw up all sorts of waiting behaviors. Secondly use save_and_open_screenshot to get a picture of what the page actually looks like before you are trying to click the link.
I'm guessing you'll see that the link isn't actually visible at that point and your test is missing a step a user would have to do to make the link visible, is it in a menu where you have to hover over a different element first? is it in a popup where you have to click on something else first?, does it need to be scrolled to? etc.
Finally, you'll generally have less issues if you stick with Chrome via Selenium. Poltergeist uses PhantomJS which hasn't been updated in quite some time and doesn't support modern JS or CSS which can lead to all sorts of strangeness.
In my code i am opening a browser as follow :-
Capybara.current_driver = :selenium
include Capybara::DSL
describe 'Auro' do
specify "OMX Manual Order" do
visit 'https://omx.ordermotion.com/en/console.asp'
end
How can i close this browser?
Have Tried following ,but no luck:-
Capybara.current_session.driver.reset!
page.execute_script "window.close();"
If you're only using selenium, then the following should work:
page.driver.quit
However, if you ever want to switch between different webdrivers, then you might want to add a condition or two. This is what I use:
page.driver.quit unless (Capybara.current_driver == :webkit || Capybara.current_driver == :sauce)
:webkit refers to the headless capybara-webkit and :sauce refers to Sauce Labs, but you can use that code for whichever webdrivers you want to use.
Hope that helps!
Try some of these
page.driver.browser.close
or
window = page.current_window
window.close
Keep in mind that if you have no other windows to switch to, an error will be raised
Try giving this a shot:
page.execute_script "window.close();"
I am trying to extract mixed mode content using Capybara. I did it using Nokogiri, but wonder why similar is not possible with Capybara.
require 'nokogiri'
doc = Nokogiri::HTML("<h1><em>Name</em>A Johnson </h1>")
puts doc.at_xpath("//h1/text()").content
It works, but when I try same XPath selector in Capybara it doesn't work.
visit('http://stackoverflow.com')
puts find(:xpath, "//h1/text()").text
It raises error:
[remote server] file:///tmp/webdriver-profile20120915-8089-kxrvho/extensions/fxdriver#googlecode.com/components/driver_component.js:6582:in `unknown': The given selector //h1/text() is either invalid or does not result in a WebElement. The following error occurred: (Selenium::WebDriver::Error::InvalidSelectorError)
[InvalidSelectorError] The result of the xpath expression "//h1/text()" is: [object Text]. It should be an element.
How to extract this text?
Capybara requires a driver, and the XPath will be executed by the driver. From your error message, it is clear you are using selenium-webdriver, which will use a browser's native XPath implementation where available. For IE, it usees its own.
You appear to be using a combination where the XPath implementation is not fully compliant. You can try to change the driver or browser, but if you really want to use Nokogiri to extract content, you should be able to do the following:
doc = Nokogiri::HTML(page.html)
puts doc.at_xpath("//h1/text()").content
I do not believe Capybara or Selenium-Webdriver have any support for directly accessing text nodes. However, if you do not want to use nokogiri, you can use selenium-webdriver to execute javascript.
You can do this (in Capybara using Selenium-Webdriver):
element = page.find('h1').native
puts page.driver.browser.execute_script("return arguments[0].childNodes[1].textContent", element)
#=> A Johnson