Appium_capybara driver + Applitools integration - capybara

I'm using RSpec framework with capybara + eyes_selenium for visual testing, and i want to integrate mobile visual testing. i installed the appium_capybara, and it works with a remote appium server that functions as a node in my remote selenium hub.
So far it works great, I've managed to login to my iOs simulator and interact with the page. The problem is integrating this whole thing with applitools.
i'm using the gem eyes_selenium, but i can't seem to perform Eyes.open with my Appium::Capybara::Driver object, getting an exception that this driver is Unknown.
Eyes.open(app_name: 'Applitools', test_name: test_name, viewport_size: viewport_size, driver: Capybara.page.driver)
anyone managed to make it work ?

Looking at the source for the eyes_selenium gem, the only place that error can come from is from the eyes_driver method - https://github.com/applitools/eyes.sdk.ruby/blob/master/lib/applitools/selenium/eyes.rb#L39 - which is implemented as below
def eyes_driver(driver, eyes = nil)
if driver.respond_to? :driver_for_eyes
driver.driver_for_eyes eyes
elsif defined?(::Capybara::Poltergeist) && (driver.is_a? ::Capybara::Poltergeist::Driver)
Applitools::Poltergeist::Driver.new(eyes, driver: driver)
else
unless driver.is_a?(Applitools::Selenium::Driver)
Applitools::EyesLogger.warn("Unrecognized driver type: (#{driver.class.name})!")
is_mobile_device = driver.respond_to?(:capabilities) && driver.capabilities['platformName']
Applitools::Selenium::Driver.new(eyes, driver: driver, is_mobile_device: is_mobile_device)
end
raise Applitools::EyesError.new "Unknown driver #{driver}!"
end
end
At a first glance the else section of that looks fully broken to me (why create a new instance of Applitools::Selenium::Driver just to then raise an error?). However, that leaves only a few possibilities for why it's not working for you,
Appium::Capybara::Driver is not a driver type supported by the eyes_selenium gem
You're not requiring the files needed to patch Appium::Capybara::Driver to be supported, such as 'applitools/capybara', although after a quick look through the eyes_selenium code I don't think it adds the driver_for_eyes method to any ancestor class of Appium::Capybara::Driver (does patch Appium::Driver though) so #1 is probably more likely.

Related

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

RubyGem 'steam-condenser' - .fetch method only time and fetch_games undefined method `[]'

I am trying to get some basic information from the Steam Community via the steam-condenser gem and so far the Steam.new seems to work just fine with all the players information.
however when I do this (example)
player = SteamId.new("tiger")
stats = player.fetch_games
I get the following error message
Traceback (most recent call last):
1: from lib/assets/ruby/test.rb:15:in `<main>'
/home/zigs/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/steam-condenser-1.3.11/lib/steam/community/steam_id.rb:326:in `fetch_games': undefined method `[]' for nil:NilClass (NoMethodError)
A lot of the information I need seems to be connected to the fetch_games (for example the method total_playtime(id))
Not sure why this is not working. I am lost. Any help or ideas are highly appreciated! Thank you!
TLDR; it looks like this gem no longer works.
the particular module that you're having trouble with is:
def fetch_games
games_data = parse "#{base_url}/games?xml=1"
#games = {}
#recent_playtimes = {}
#total_playtimes = {}
games_data['games']['game'].each do |game_data|
app_id = game_data['appID'].to_i
#games[app_id] = SteamGame.new app_id, game_data
recent = game_data['hoursLast2Weeks'].to_f
total = (game_data['hoursOnRecord'] || '').delete(',').to_f
#recent_playtimes[app_id] = (recent * 60).to_i
#total_playtimes[app_id] = (total * 60).to_i
end
true
end
with the particular problem statement being games_data['games']['game'].each
If we were looking to get information for a particular user, it downloads an XML document about the user from a URL looking like:
http://steamcommunity.com/id/demomenz?xml=1
and this file does not seem to contain any games objects in it.
Having looked at the codebase for the steam-condenser gem; it hasn't really been updated in about 6 years. I can only assume that the XML format has been modified since this time and that the gem will no longer work.
Valve has added more privacy options to Steam Community profiles which are not reflected in the old XML APIs.
Apparently, the profile in question (tiger) has it‘s game details set to “Friends Only” or ”Private” as games are also unavailable in the browser.
The code from the released 1.x versions is no longer guaranteed to work when it comes to Steam Community. Valve deprecated the old XML APIs several years ago. Sadly, the modern Web API hasn‘t gotten much attention from Valve‘s side either. So development of Steam Condenser has mostly come to halt, too.
You might have more luck using the code from the master branch of the GitHub repository which uses Web API for most of the Community features.
You will have to register for a Steam Web API key, though: https://steamcommunity.com/dev/apikey

Selecting an option with select2 and Capybara running Cucumber test

I have a select2 v4 that loads options through AJAX.
I am running a Cucumber test where I need to select 2 options of the list, but I can't seem to make the list open up and load (which normally gets populated when I type 2 or characters).
I have tried:
As suggested here:
#session.execute_script("$('#publish_to').select2('open')")
and
#session.first(".input.publish_to .select2-container").click
and
#session.first("#publish_to").find(".select2-choice").click
which do not give me an error, but I am not getting the options to select, so I am assuming that the click is not really working. Things I have tried to select the options:
# This one cannot find the css:
#session.find(".select2-results__options", text: client.email).click
# This one gives me a Timeout error
#session.evaluate_script "$('#publish_to').val(#{client.id}).trigger('change')"
# This one gives me a Timeout error
#session.evaluate_script "$('.select2-search__field').trigger('keydown').val('#{client.email}').trigger('keyup')";
sleep 10
#session.find('.select2-search__option', text: client.email).click
Anything with trigger gives me a Timeout error, so I tried waiting for jQuery.active but I never got a true even waiting for 2 minutes:
counter = 0
timeout_in_sec = 120
while counter < timeout_in_sec && #session.evaluate_script('jQuery.active').zero?
sleep 1.second
counter+=1
end
I tried using the gem capybara-select2 running:
#session.select2 client.email, css: '#publish_to', search: true
but I get the error undefined methodselect2' for #and I haveWorld(CapybaraSelect2)in myenv.rb`
I am using Cucumber v3.1.2 with ruby gem 'cucumber-rails'
The poltergeist driver is roughly equivalent to a 7 year old version of Safari which means it doesn't support a lot of current JS/CSS. This means your issue could simply be that select2 is no longer compatible with Poltergeist (without a lot of polyfilling). You're going to be much better off updating to using a real browser (stable - chrome via selenium, etc) or one of the direct to Chrome drivers (highly beta) that have spun off Poltergeist (Apparition is one of them). Those will allow you to run with a visible browser (useful for debugging) or headless.
The following code uses Chrome via selenium and interacts with the select2 demo site to select an entry that is loaded via Ajax.
require "selenium/webdriver"
require "capybara/dsl"
sess = Capybara::Session.new(:selenium_chrome)
sess.visit("https://select2.org/data-sources/ajax")
sess.first('.select2-container', minimum: 1).click
sess.find('.select2-dropdown input.select2-search__field').send_keys("capy")
sleep 5 # just to watch the browser search
sess.find('.select2-results__option', text: 'teamcapybara/capybara').click
sess.assert_selector(:css, '.select2-selection__rendered', text: 'teamcapybara/capybara')
sleep 5 # just to see the effect

tmr.create() fails in dirt simple code

On an ESP8266, a LUA tmr.create() fails. Just a single line of code from the nodemcu docs. I've yet to get this working; stumped; have found nothing on the 'net here or forums. Posted in several other places with no replies. Odd
Basic node commands work. And, here's the thing that's getting me: some timer functions work - for instance tmr.alarm() does - but tmr.create() doesn't.
QUESTION 1: if the tmr module is loaded, isn't the entire module loaded, not just parts of it?
When I try this one line copied directly from the NodeMCU docs, it fails:
local mytimer = tmr.create()
with the usual message, I understand to mean an object is undefined:
stdin:1: attempt to call field 'create' (a nil value)
QUESTION 2: What am I missing or doing wrong?
Nodemcu's flasher successfully sent its default
INTERNAL://NODEMCU # 0x00000
NodeMCU 0.9.5 build 20150318
The board is an Adafruit Huzzah ESP8266, not a NodeMCU board. They both use the same ESP12, I think, so that shouldn't matter (or I hope it doesn't :-/)
NodeMCU 0.9.5 build 20150318
There's your culprit. That version is ancient. create() was added much later. Build a recent version from the master branch, https://nodemcu.readthedocs.io/en/master/en/build/ (note master in the URL), and flash that one.

Use cache money only for a single model?

I want to use cache-money but I don't want to start automatically caching everything (I'm working with a large production app, terabytes of data etc). How do I use it for only the models that I specify? Right now I've got:
# initializers/cache_money.rb
require 'cache_money'
config = (cfg = YAML.load(IO.read(File.join(RAILS_ROOT, "config", "memcached.yml"))))[RAILS_ENV] || cfg["defaults"]
$memcache = MemCache.new(config)
$memcache.servers = config['servers']
$local = Cash::Local.new($memcache)
$lock = Cash::Lock.new($memcache)
$cache = Cash::Transactional.new($local, $lock)
and then in the model I want to cache with cache-money:
# my_model.rb
class MyModel < ActiveRecord::Base
is_cached :repository => $cache
# ...
end
But this doesn't work; the call to is_cached gives the following error: NoMethodError: undefined method `create' for Config:Module
Any ideas? Failing that, is there anywhere I can go for help with cache-money? I couldn't find a mailing list or anything.
I think this is a bug in the cache_money code.
There are forks available on github that fix this bug, eg:
http://github.com/quake/cache-money
The fix can be seen with this commit:
http://github.com/quake/cache-money/commit/54c3d12789f31f2904d1fe85c102d7dbe5829590
I've just experienced the same problem trying to deploy an application. Running on my development machine it was fine, but it failed with this error on the production machine.
Apart from the architecture (OSX vs CentOS) the only difference i could see was that the ruby versions were different (1.8.6 p114 vs 1.8.6 p0). After upgrading the server to the latest 1.8 version (1.8.7 p160) this error went away.

Resources