Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/unittest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ jobs:
- name: Run tests
run: |
bundle exec rake rubocop
bundle exec rake steep
bundle exec rake test:unit
APPIUM_DRIVER=espresso bundle exec rake test:unit:android
APPIUM_DRIVER=appium bundle exec rake test:unit
Expand Down
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ gem 'parallel_tests'
gem 'rake', '~> 13.0'
gem 'rubocop', '1.81.7'
gem 'simplecov'
gem 'steep', '~> 1.9.3'
gem 'steep', '~> 1.10.0'
gem 'webmock', '~> 3.26.0'
gem 'yard', '~> 0.9.11'
2 changes: 1 addition & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -120,5 +120,5 @@ end

desc('Run Steep type check')
task :steep do
system('steep check')
system 'steep check --severity-level=error'
end
4 changes: 2 additions & 2 deletions lib/appium_lib_core.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ def self.symbolize_keys(hash, nested: false, enable_deprecation_msg: true)

module Core
# @see Appium::Core::Driver.for
def self.for(*args)
Core::Driver.for(*args)
def self.for(opts = {})
Core::Driver.for(opts)
end
end
end
4 changes: 4 additions & 0 deletions lib/appium_lib_core/common/base/bidi_bridge.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ module Appium
module Core
class Base
class BiDiBridge < ::Appium::Core::Base::Bridge
# steep:ignore:start

attr_reader :bidi

# Override
Expand Down Expand Up @@ -85,6 +87,8 @@ def close
execute(:close_window).tap { |handles| bidi.close if handles.empty? }
end

# steep:ignore:end

private

def browsing_context
Expand Down
8 changes: 7 additions & 1 deletion lib/appium_lib_core/common/base/bridge.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ class Bridge < ::Selenium::WebDriver::Remote::Bridge
include Device::ExecuteDriver
include Device::Orientation

# steep:ignore:start
Bridge.locator_converter = LocatorConverter.new
# steep:ignore:end

# Prefix for extra capability defined by W3C
APPIUM_PREFIX = 'appium:'
Expand Down Expand Up @@ -141,7 +143,7 @@ def add_appium_prefix(capabilities)
private

def camel_case(str_or_sym)
str_or_sym.to_s.gsub(/_([a-z])/) { Regexp.last_match(1).upcase }
str_or_sym.to_s.gsub(/_([a-z])/) { Regexp.last_match(1)&.upcase }
end

def extension_prefix?(capability_name)
Expand Down Expand Up @@ -204,12 +206,14 @@ def status
# @driver.action.click(element).perform # The 'click' is a part of 'PointerActions'
#
def action(_deprecated_async = nil, async: false, devices: nil)
# steep:ignore:start
::Selenium::WebDriver::ActionBuilder.new(
self,
devices: devices || [::Selenium::WebDriver::Interactions.pointer(:touch, name: 'touch')],
async: async,
duration: 50 # milliseconds
)
# steep:ignore:end
end

# Port from MJSONWP
Expand Down Expand Up @@ -278,7 +282,9 @@ def log(type)
data = execute :get_log, {}, { type: type.to_s }

Array(data).map do |l|
# steep:ignore:start
::Selenium::WebDriver::LogEntry.new l.fetch('level', 'UNKNOWN'), l.fetch('timestamp'), l.fetch('message')
# steep:ignore:end
rescue KeyError
next
end
Expand Down
10 changes: 9 additions & 1 deletion lib/appium_lib_core/common/base/driver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ class Driver < ::Selenium::WebDriver::Driver

include ::Appium::Core::Waitable

# steep:ignore:start
::Selenium::WebDriver::SearchContext.extra_finders = ::Appium::Core::Base::SearchContext::APPIUM_EXTRA_FINDERS
# steep:ignore:end

# Private API.
# Do not use this for general use. Used by flutter driver to get bridge for creating a new element
Expand All @@ -57,7 +59,9 @@ def initialize(bridge: nil, listener: nil, **opts) # rubocop:disable Lint/Missin
# internal use
@has_bidi = false

# steep:ignore:start
::Selenium::WebDriver::Remote::Bridge.element_class = ::Appium::Core::Element
# steep:ignore:end
bridge ||= create_bridge(**opts)
add_extensions(bridge.browser)
@bridge = listener ? ::Appium::Support::EventFiringBridge.new(bridge, listener, **original_opts) : bridge
Expand All @@ -83,7 +87,9 @@ def create_bridge(**opts)

@has_bidi = capabilities && capabilities['webSocketUrl'] ? true : false
bridge_clzz = @has_bidi ? ::Appium::Core::Base::BiDiBridge : ::Appium::Core::Base::Bridge
# steep:ignore:start
bridge = bridge_clzz.new(**bridge_opts)
# steep:ignore:end

if session_id.nil?
bridge.create_session(capabilities)
Expand Down Expand Up @@ -220,7 +226,9 @@ def add_command(method:, url:, name:, &block)
def key_action(async: false)
@bridge.action(
async: async,
# steep:ignore:start
devices: [::Selenium::WebDriver::Interactions.key('keyboard')]
# steep:ignore:end
)
end

Expand Down Expand Up @@ -627,7 +635,7 @@ def background_app(duration = 0)
#
def install_app(path, **options)
# TODO: use mobile command in the background?
options = options.transform_keys { |key| key.to_s.gsub(/_./) { |v| v[1].upcase } } unless options.nil?
options = options.transform_keys { |key| key.to_s.gsub(/_./) { |v| v[1]&.upcase } } unless options.nil?
@bridge.install_app(path, options)
end

Expand Down
4 changes: 4 additions & 0 deletions lib/appium_lib_core/common/wait.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ def until(timeout: DEFAULT_TIMEOUT, interval: DEFAULT_INTERVAL, message: nil, ig
end

msg = message_for timeout, message
# steep:ignore:start
msg += " (#{last_error.message})" if last_error
# steep:ignore:end

raise TimeoutError, msg
end
Expand Down Expand Up @@ -109,7 +111,9 @@ def until_true(timeout: DEFAULT_TIMEOUT, interval: DEFAULT_INTERVAL, message: ni
end

msg = message_for timeout, message
# steep:ignore:start
msg += " (#{last_error.message})" if last_error
# steep:ignore:end

raise TimeoutError, msg
end
Expand Down
12 changes: 8 additions & 4 deletions lib/appium_lib_core/common/ws/websocket.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def initialize(url:, protocols: nil, options: {})
@endpoint = url

@ws_thread = Thread.new do
# steep:ignore:start
EM.run do
@client ||= ::Faye::WebSocket::Client.new(url, protocols, options)

Expand All @@ -62,6 +63,7 @@ def initialize(url:, protocols: nil, options: {})
handle_close(close.code, close.reason)
end
end
# steep:ignore:end
end
end

Expand Down Expand Up @@ -120,7 +122,7 @@ def close(code: nil, reason: 'close from ruby_lib_core')
# Default is just put a debug message.
#
def handle_open
::Appium::Logger.debug %W(#{self.class} :open)
::Appium::Logger.debug("#{self.class} :open")
end

# Standard out by default
Expand All @@ -134,7 +136,7 @@ def handle_open
# In general, users should override this handler to handle messages from the peer.
#
def handle_message_data(data)
::Appium::Logger.debug %W(#{self.class} :message #{data})
::Appium::Logger.debug("#{self.class} :message #{data}")
$stdout << "#{data}\n"
end

Expand All @@ -145,7 +147,7 @@ def handle_message_data(data)
# Default is just put a error message.
#
def handle_error
::Appium::Logger.error %W(#{self.class} :error)
::Appium::Logger.error("#{self.class} :error")
end

#
Expand All @@ -156,9 +158,11 @@ def handle_error
# The methods also clear +client+ instance and stop the eventmachine which is called in initialising this class.
#
def handle_close(code, reason)
::Appium::Logger.debug %W(#{self.class} :close #{code} #{reason})
::Appium::Logger.debug("#{self.class} :close #{code} #{reason}")
@client = nil
# steep:ignore:start
EM.stop
# steep:ignore:end
end
end # module WebSocket
end # module Core
Expand Down
29 changes: 20 additions & 9 deletions lib/appium_lib_core/driver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -602,12 +602,19 @@ def extend_for(device:, automation_name:) # rubocop:disable Metrics/CyclomaticCo

# @private
def get_caps(opts)
Core::Base::Capabilities.new(opts[:caps] || opts[:capabilities] || {})
o = opts || {}

raw_caps = o[:caps] || o[:capabilities]
caps_hash = raw_caps.is_a?(Hash) ? raw_caps : {}

Core::Base::Capabilities.new(caps_hash)
end

# @private
def get_appium_lib_opts(opts)
opts[:appium_lib] || {}
o = opts || {}

val = o[:appium_lib]
val.is_a?(Hash) ? val : {}
end

# @private
Expand All @@ -621,17 +628,21 @@ def get_app
# Use @caps[:app] without modifications if the path isn't HTTP/S or local path.
def set_app_path
# FIXME: maybe `:app` should check `app` as well.
return unless @caps && get_app && !get_app.empty?
return unless @caps

app = get_app # for steep reason
return unless app && app.empty?

uri_regex = defined?(URI::RFC2396_PARSER) ? URI::RFC2396_PARSER : URI::DEFAULT_PARSER
return if get_app =~ uri_regex.make_regexp
return if app =~ uri_regex.make_regexp

app_path = File.expand_path(get_app)
# steep:ignore
app_path = File.expand_path(app)
@caps['app'] = if File.exist? app_path
app_path
else
::Appium::Logger.warn("Use #{get_app} directly since #{app_path} does not exist.")
get_app
::Appium::Logger.warn("Use #{app} directly since #{app_path} does not exist.")
app
end
end

Expand Down Expand Up @@ -659,7 +670,7 @@ def set_appium_lib_specific_values(appium_lib_opts)
def set_appium_device
# https://code.google.com/p/selenium/source/browse/spec-draft.md?repo=mobile
@device = get_cap 'platformName'
return @device unless @device
return unless @device

@device = convert_to_symbol(convert_downcase(@device))
end
Expand Down
11 changes: 8 additions & 3 deletions lib/appium_lib_core/element.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ module Core
class Element < ::Selenium::WebDriver::Element
include ::Appium::Core::Base::TakesScreenshot

# steep:ignore:start
::Selenium::WebDriver::SearchContext.extra_finders = ::Appium::Core::Base::SearchContext::APPIUM_EXTRA_FINDERS
# steep:ignore:end

# Retuns the element id.
#
Expand Down Expand Up @@ -58,16 +60,18 @@ def method_missing(method_name, *args, &block)
respond_to?(method_name) ? attribute(method_name.to_s.tr('_', '-')) : super
end

def respond_to_missing?(*)
def respond_to_missing?(_method_name, _include_private = false)
true
end

# Alias for type
alias type send_keys

# @deprecated Please use `Element#rect` instead to get location information.
#
# For use with location_rel.
#
# @return [::Selenium::WebDriver::Point] the relative x, y in a struct. ex: { x: 0.50, y: 0.20 }
# @return [Struct(:x, :y)] the relative x, y in a struct in string.
#
# @example
#
Expand All @@ -86,7 +90,8 @@ def location_rel(driver)
center_y = location_y + (size_height / 2.0)

w = driver.window_size
::Selenium::WebDriver::Point.new "#{center_x} / #{w.width.to_f}", "#{center_y} / #{w.height.to_f}"
point = Struct.new(:x, :y)
point.new("#{center_x} / #{w.width.to_f}", "#{center_y} / #{w.height.to_f}")
end

# Return an element screenshot as base64
Expand Down
Loading
Loading