Skip to content

Commit 21ed1cd

Browse files
committed
first try at implementation
1 parent a8052bc commit 21ed1cd

4 files changed

Lines changed: 34 additions & 69 deletions

File tree

lib/appium_lib_core/common/base/bridge.rb

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,6 @@ class Bridge < ::Selenium::WebDriver::Remote::Bridge
4747
# No 'browserName' means the session is native appium connection
4848
APPIUM_NATIVE_BROWSER_NAME = 'appium'
4949

50-
attr_reader :available_commands
51-
5250
def browser
5351
@browser ||= begin
5452
name = @capabilities&.browser_name
@@ -74,7 +72,6 @@ def browser
7472
# )
7573
#
7674
def attach_to(session_id, platform_name, automation_name)
77-
@available_commands = ::Appium::Core::Commands::COMMANDS.dup
7875
@session_id = session_id
7976

8077
# generate a dummy capabilities instance which only has the given platformName and automationName
@@ -109,8 +106,6 @@ def attach_to(session_id, platform_name, automation_name)
109106
# driver = core.start_driver
110107
#
111108
def create_session(capabilities)
112-
@available_commands = ::Appium::Core::Commands::COMMANDS.dup
113-
114109
always_match = add_appium_prefix(capabilities)
115110
response = execute(:new_session, {}, { capabilities: { alwaysMatch: always_match, firstMatch: [{}] } })
116111

@@ -162,29 +157,16 @@ def json_create(value)
162157

163158
public
164159

165-
# command for Appium 2.0.
166-
167-
# Example:
168-
# driver.add_command(name: :available_contexts, method: :get, url: 'session/:session_id/contexts') do
169-
# execute(:available_contexts, {}) || []
170-
# end
171-
# Then,
172-
# driver.available_contexts #=> ["NATIVE_APP"]
173-
174-
# def add_command(method:, url:, name:, &block)
175-
# Bridge.add_command name, method, url, &block
176-
# end
177-
178-
def add_command(method:, url:, name:, &block)
179-
::Appium::Logger.info "Overriding the method '#{name}' for '#{url}'" if @available_commands.key? name
180-
181-
@available_commands[name] = [method, url]
182-
183-
::Appium::Core::Device.add_endpoint_method name, &block
160+
# Override Selenium's command_list to use Appium's command definitions
161+
# instead of the default W3C COMMANDS from Selenium.
162+
def command_list
163+
::Appium::Core::Commands::COMMANDS
184164
end
185165

166+
# Override Selenium's commands to resolve extra_commands from this subclass
167+
# rather than the parent Selenium::WebDriver::Remote::Bridge.
186168
def commands(command)
187-
@available_commands[command] || Bridge.extra_commands[command]
169+
command_list[command] || self.class.extra_commands&.[](command)
188170
end
189171

190172
def status

lib/appium_lib_core/common/base/driver.rb

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -135,25 +135,21 @@ def update_sending_request_to(protocol:, host:, port:, path:)
135135
# drivers/plugins in Appium 2.0. Appium 2.0 and its custom drivers/plugins allow you
136136
# to define custom commands that are not part of W3C spec.
137137
#
138+
# Uses Selenium's +Bridge.add_command+ under the hood to register the command
139+
# and define the method on the bridge.
140+
#
138141
# @param [Symbol] method HTTP request method as https://www.w3.org/TR/webdriver/#endpoints
139142
# @param [string] url The url to URL template as https://www.w3.org/TR/webdriver/#endpoints.
140143
# +:session_id+ is the placeholder of 'session id'.
141144
# Other place holders can be specified with +:+ prefix like +:id+.
142145
# Then, the +:id+ will be replaced with a given value as the seconds argument of +execute+
143146
# @param [Symbol] name The name of method that is called as the driver instance method.
144-
# @param [Proc] block The block to involve as the method.
145-
# Please define a method that has the same +name+ with arguments you want.
146-
# The method must has +execute+ method. tHe +execute+ is calls the +url+
147-
# with the given parameters.
148-
# The first argument should be +name+ as symbol.
149-
# The second argument should be hash. If keys in the hash matches +:+ prefix
150-
# string in the given url, the matched string in the given url will be
151-
# values in the hash.
152-
# The third argument should be hash. The hash will be the request body.
153-
# Please read examples below for more details.
147+
# @param [Proc] block The block becomes the method body. It is executed in the context of
148+
# the bridge instance, so +execute+ is available. When no block is given,
149+
# a default implementation calling +execute(name)+ is used.
154150
# @raise [ArgumentError] If the given +method+ is invalid value.
155151
#
156-
# @example
152+
# @example Simple GET command (no block)
157153
#
158154
# @driver.add_command(
159155
# method: :get,
@@ -163,42 +159,39 @@ def update_sending_request_to(protocol:, host:, port:, path:)
163159
# # Send a GET request to 'session/<session id>/path/to/custom/url'
164160
# @driver.test_command
165161
#
162+
# @example POST command with arguments (block style)
166163
#
167164
# @driver.add_command(
168165
# method: :post,
169166
# url: 'session/:session_id/path/to/custom/url',
170167
# name: :test_command
171-
# ) do
172-
# def test_command(argument)
173-
# execute(:test_command, {}, { dummy: argument })
174-
# end
175-
# end
176-
# # Send a POST request to 'session/<session id>/path/to/custom/url'
177-
# # with body "{ dummy: 1 }" as JSON object. "1" is the argument.
178-
# # ':session_id' in the given 'url' is replaced with current 'session id'.
168+
# ) { |argument| execute(:test_command, {}, { dummy: argument }) }
179169
# @driver.test_command(1)
180170
#
171+
# @example POST command with URL placeholders (block style)
181172
#
182173
# @driver.add_command(
183174
# method: :post,
184175
# url: 'session/:session_id/element/:id/custom/action',
185176
# name: :test_action_command
186-
# ) do
187-
# def test_action_command(element_id, action)
188-
# execute(:test_action_command, {id: element_id}, { dummy_action: action })
189-
# end
190-
# end
191-
# # Send a POST request to 'session/<session id>/element/<element id>/custom/action'
192-
# # with body "{ dummy_action: #{action} }" as JSON object. "action" is the seconds argument.
193-
# # ':session_id' in the given url is replaced with current 'session id'.
194-
# # ':id' in the given url is replaced with the given 'element_id'.
177+
# ) { |element_id, action| execute(:test_action_command, {id: element_id}, { dummy_action: action }) }
195178
# e = @driver.find_element :accessibility_id, 'an element'
196179
# @driver.test_action_command(e.id, 'action')
197180
#
198181
def add_command(method:, url:, name:, &block)
199182
raise ::Appium::Core::Error::ArgumentError, "Available method is either #{AVAILABLE_METHODS}" unless AVAILABLE_METHODS.include? method
200183

201-
@bridge.add_command method: method, url: url, name: name, &block
184+
if Bridge.extra_commands&.key?(name)
185+
::Appium::Logger.info "Overriding the command '#{name}' for '#{url}'"
186+
end
187+
188+
# Use Selenium's Bridge.add_command to register the command and define the method.
189+
# When no block is given, create a default implementation that calls execute.
190+
block ||= proc { execute(name) }
191+
Bridge.add_command(name, method, url, &block)
192+
193+
# Ensure the driver delegates the new method to bridge
194+
self.class.class_eval { def_delegator :@bridge, name } unless self.class.method_defined?(name)
202195
end
203196

204197
### Methods for Appium

sig/lib/appium_lib_core/common/base/bridge.rbs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ module Appium
1010

1111
@browser: untyped
1212

13-
@available_commands: untyped
14-
1513
@session_id: untyped
1614

1715
# generate a dummy capabilities instance which only has the given platformName and automationName
@@ -51,8 +49,6 @@ module Appium
5149
# No 'browserName' means the session is native appium connection
5250
APPIUM_NATIVE_BROWSER_NAME: "appium"
5351

54-
attr_reader available_commands: untyped
55-
5652
def browser: () -> untyped
5753

5854
# Appium only.
@@ -115,8 +111,10 @@ module Appium
115111

116112
public
117113

118-
def add_command: (method: untyped, url: untyped, name: untyped) { (?) -> untyped } -> untyped
114+
# Override Selenium's command_list to use Appium's command definitions
115+
def command_list: () -> Hash[Symbol, Array[Symbol | String]]
119116

117+
# Override Selenium's commands to resolve extra_commands from this subclass
120118
def commands: (untyped command) -> untyped
121119

122120
def status: () -> untyped

test/unit/android/webdriver/w3c/commands_test.rb

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,7 @@ def test_add_command_block
5050
method: :post,
5151
url: 'session/:session_id/path/to/custom/url',
5252
name: :test_command
53-
) do
54-
def test_command(argument)
55-
execute(:test_command, {}, { dummy: argument })
56-
end
57-
end
53+
) { |argument| execute(:test_command, {}, { dummy: argument }) }
5854

5955
assert_equal @driver.respond_to?(:test_command), true
6056

@@ -72,11 +68,7 @@ def test_add_command_block_element_id
7268
method: :post,
7369
url: 'session/:session_id/path/to/custom/:element_id/url',
7470
name: :test_command
75-
) do
76-
def test_command(argument)
77-
execute(:test_command, { element_id: 'dummy_element_id' }, { dummy: argument })
78-
end
79-
end
71+
) { |argument| execute(:test_command, { element_id: 'dummy_element_id' }, { dummy: argument }) }
8072

8173
assert_equal @driver.respond_to?(:test_command), true
8274

0 commit comments

Comments
 (0)