-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update edge testing for Chrome based Edge on MacOS
- Loading branch information
Showing
9 changed files
with
257 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
source "https://rubygems.org" | ||
|
||
gem 'bundler', '< 3.0' | ||
gemspec path: '..' | ||
|
||
gem 'xpath', github: 'teamcapybara/xpath' | ||
|
||
gem 'selenium-webdriver', github: 'seleniumhq/selenium', glob: 'rb/*.gemspec' | ||
gem 'webdrivers', github: 'twalpole/webdrivers', branch: 'selenium_4' | ||
gem 'rack', github: 'rack/rack' | ||
gem 'sinatra', github: 'sinatra/sinatra', branch: 'master' | ||
|
||
gem 'puma', github: 'puma/puma' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
117 changes: 117 additions & 0 deletions
117
lib/capybara/selenium/driver_specializations/edge_driver.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'capybara/selenium/nodes/edge_node' | ||
|
||
module Capybara::Selenium::Driver::EdgeDriver | ||
def fullscreen_window(handle) | ||
return super if edgedriver_version < 75 | ||
|
||
within_given_window(handle) do | ||
begin | ||
super | ||
rescue NoMethodError => e | ||
raise unless e.message.match?(/full_screen_window/) | ||
|
||
result = bridge.http.call(:post, "session/#{bridge.session_id}/window/fullscreen", {}) | ||
result['value'] | ||
end | ||
end | ||
end | ||
|
||
def resize_window_to(handle, width, height) | ||
super | ||
rescue Selenium::WebDriver::Error::UnknownError => e | ||
raise unless e.message.match?(/failed to change window state/) | ||
|
||
# Chromedriver doesn't wait long enough for state to change when coming out of fullscreen | ||
# and raises unnecessary error. Wait a bit and try again. | ||
sleep 0.25 | ||
super | ||
end | ||
|
||
def reset! | ||
return super if edgedriver_version < 75 | ||
# Use instance variable directly so we avoid starting the browser just to reset the session | ||
return unless @browser | ||
|
||
switch_to_window(window_handles.first) | ||
window_handles.slice(1..-1).each { |win| close_window(win) } | ||
|
||
timer = Capybara::Helpers.timer(expire_in: 10) | ||
begin | ||
@browser.navigate.to('about:blank') | ||
clear_storage unless uniform_storage_clear? | ||
wait_for_empty_page(timer) | ||
rescue *unhandled_alert_errors | ||
accept_unhandled_reset_alert | ||
retry | ||
end | ||
|
||
execute_cdp('Storage.clearDataForOrigin', origin: '*', storageTypes: storage_types_to_clear) | ||
end | ||
|
||
def download_path=(path) | ||
return @browser.download_path=(path) if @browser.respond_to?(:download_path) | ||
|
||
# Not yet implemented in seleniun-webdriver for edge so do it ourselves | ||
execute_cdp('Page.setDownloadBehavior', behavior: 'allow', downloadPath: path) | ||
end | ||
|
||
private | ||
|
||
def storage_types_to_clear | ||
types = ['cookies'] | ||
types << 'local_storage' if clear_all_storage? | ||
types.join(',') | ||
end | ||
|
||
def clear_all_storage? | ||
options.values_at(:clear_session_storage, :clear_local_storage).none? { |s| s == false } | ||
end | ||
|
||
def uniform_storage_clear? | ||
clear = options.values_at(:clear_session_storage, :clear_local_storage) | ||
clear.all? { |s| s == false } || clear.none? { |s| s == false } | ||
end | ||
|
||
def clear_storage | ||
# Chrome errors if attempt to clear storage on about:blank | ||
# In W3C mode it crashes chromedriver | ||
url = current_url | ||
super unless url.nil? || url.start_with?('about:') | ||
end | ||
|
||
def delete_all_cookies | ||
execute_cdp('Network.clearBrowserCookies') | ||
rescue *cdp_unsupported_errors | ||
# If the CDP clear isn't supported do original limited clear | ||
super | ||
end | ||
|
||
def cdp_unsupported_errors | ||
@cdp_unsupported_errors ||= [Selenium::WebDriver::Error::WebDriverError] | ||
end | ||
|
||
def execute_cdp(cmd, params = {}) | ||
args = { cmd: cmd, params: params } | ||
result = bridge.http.call(:post, "session/#{bridge.session_id}/goog/cdp/execute", args) | ||
result['value'] | ||
end | ||
|
||
def build_node(native_node, initial_cache = {}) | ||
::Capybara::Selenium::EdgeNode.new(self, native_node, initial_cache) | ||
end | ||
|
||
def bridge | ||
browser.send(:bridge) | ||
end | ||
|
||
def edgedriver_version | ||
@edgedriver_version ||= begin | ||
caps = browser.capabilities | ||
caps['chrome']&.fetch('chromedriverVersion', nil).to_f | ||
end | ||
end | ||
end | ||
|
||
Capybara::Selenium::Driver.register_specialization :edge, Capybara::Selenium::Driver::EdgeDriver |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'capybara/selenium/extensions/html5_drag' | ||
|
||
class Capybara::Selenium::EdgeNode < Capybara::Selenium::Node | ||
include Html5Drag | ||
|
||
def set_text(value, clear: nil, **_unused) | ||
return super unless chrome_edge? | ||
|
||
super.tap do | ||
# React doesn't see the chromedriver element clear | ||
send_keys(:space, :backspace) if value.to_s.empty? && clear.nil? | ||
end | ||
end | ||
|
||
def set_file(value) # rubocop:disable Naming/AccessorMethodName | ||
# In Chrome 75+ files are appended (due to WebDriver spec - why?) so we have to clear here if its multiple and already set | ||
if chrome_edge? | ||
driver.execute_script(<<~JS, self) | ||
if (arguments[0].multiple && (arguments[0].files.length > 0)){ | ||
arguments[0].value = null; | ||
} | ||
JS | ||
end | ||
super | ||
rescue *file_errors => e | ||
raise ArgumentError, "Selenium < 3.14 with remote Chrome doesn't support multiple file upload" if e.message.match?(/File not found : .+\n.+/m) | ||
|
||
raise | ||
end | ||
|
||
def drag_to(element) | ||
return super unless chrome_edge? && html5_draggable? | ||
|
||
html5_drag_to(element) | ||
end | ||
|
||
def drop(*args) | ||
return super unless chrome_edge? | ||
html5_drop(*args) | ||
end | ||
|
||
# def click(*) | ||
# super | ||
# rescue ::Selenium::WebDriver::Error::WebDriverError => e | ||
# # chromedriver 74 (at least on mac) raises the wrong error for this | ||
# raise ::Selenium::WebDriver::Error::ElementClickInterceptedError, e.message if e.message.match?(/element click intercepted/) | ||
# | ||
# raise | ||
# end | ||
|
||
def disabled? | ||
return super unless chrome_edge? | ||
driver.evaluate_script("arguments[0].matches(':disabled, select:disabled *')", self) | ||
end | ||
# | ||
# def select_option | ||
# # To optimize to only one check and then click | ||
# selected_or_disabled = driver.evaluate_script(<<~JS, self) | ||
# arguments[0].matches(':disabled, select:disabled *, :checked') | ||
# JS | ||
# click unless selected_or_disabled | ||
# end | ||
|
||
private | ||
|
||
def file_errors | ||
@file_errors = ::Selenium::WebDriver.logger.suppress_deprecations do | ||
[::Selenium::WebDriver::Error::ExpectedError] | ||
end | ||
end | ||
|
||
def bridge | ||
driver.browser.send(:bridge) | ||
end | ||
|
||
def browser_version | ||
@browser_version ||= begin | ||
caps = driver.browser.capabilities | ||
(caps[:browser_version] || caps[:version]).to_f | ||
end | ||
end | ||
|
||
def chrome_edge? | ||
browser_version >= 75 | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters