Skip to content

Commit 9376bf2

Browse files
authored
add execuite_driver (#222)
* add execuite_driver * add element class converter * append docstring, fix test code style
1 parent 8b70c86 commit 9376bf2

File tree

15 files changed

+234
-8
lines changed

15 files changed

+234
-8
lines changed

.rubocop.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ Metrics/ParameterLists:
1818
Max: 6
1919
Lint/NestedMethodDefinition:
2020
Enabled: false
21+
# TODO: Replace <<- with <<~ after dropping Ruby 2.2
22+
Layout/IndentHeredoc:
23+
Enabled: false
2124
Style/Documentation:
2225
Enabled: false
2326
Style/CommentedKeyword:

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Read `release_notes.md` for commit level details.
55
## [Unreleased]
66

77
### Enhancements
8+
- Add `execute_driver` to run a batch script on Appium 1.14.0+
89

910
### Bug fixes
1011

lib/appium_lib_core/common/base.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
require_relative 'device/clipboard_content_type'
2929
require_relative 'device/device'
3030
require_relative 'device/touch_actions'
31+
require_relative 'device/execute_driver'
3132

3233
# The following files have selenium-webdriver related stuff.
3334
require_relative 'base/driver'

lib/appium_lib_core/common/base/bridge/mjsonwp.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class MJSONWP < ::Selenium::WebDriver::Remote::OSS::Bridge
3131
include Device::ScreenRecord::Command
3232
include Device::Device
3333
include Device::TouchActions
34+
include Device::ExecuteDriver
3435

3536
def commands(command)
3637
::Appium::Core::Commands::MJSONWP::COMMANDS[command]
@@ -53,6 +54,13 @@ def take_viewport_screenshot
5354
def send_actions(_data)
5455
raise Error::UnsupportedOperationError, '#send_actions has not been supported in MJSONWP'
5556
end
57+
58+
# For Appium
59+
# @param [Hash] id The id which can get as a response from server
60+
# @return [::Selenium::WebDriver::Element]
61+
def convert_to_element(id)
62+
::Selenium::WebDriver::Element.new self, element_id_from(id)
63+
end
5664
end # class MJSONWP
5765
end # class Bridge
5866
end # class Base

lib/appium_lib_core/common/base/bridge/w3c.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class W3C < ::Selenium::WebDriver::Remote::W3C::Bridge
3131
include Device::ScreenRecord::Command
3232
include Device::Device
3333
include Device::TouchActions
34+
include Device::ExecuteDriver
3435

3536
def commands(command)
3637
::Appium::Core::Commands::W3C::COMMANDS[command]
@@ -133,6 +134,13 @@ def find_elements_by(how, what, parent = nil)
133134
ids.map { |id| ::Selenium::WebDriver::Element.new self, element_id_from(id) }
134135
end
135136

137+
# For Appium
138+
# @param [Hash] id The id which can get as a response from server
139+
# @return [::Selenium::WebDriver::Element]
140+
def convert_to_element(id)
141+
::Selenium::WebDriver::Element.new self, element_id_from(id)
142+
end
143+
136144
# For Appium
137145
# override
138146
# called in `extend DriverExtensions::HasNetworkConnection`

lib/appium_lib_core/common/base/driver.rb

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,6 +1042,54 @@ def find_elements_by_image(img_path)
10421042
template = Base64.strict_encode64 File.read img_path
10431043
find_elements :image, template
10441044
end
1045+
1046+
# @since Appium 1.14.0
1047+
#
1048+
# Run a set of script against the current session, allowing execution of many commands in one Appium request.
1049+
# Supports {https://webdriver.io/docs/api.html WebdriverIO} API so far.
1050+
# Please read {http://appium.io/docs/en/commands/session/execute-driver command API} for more details
1051+
# about acceptable scripts and the output.
1052+
#
1053+
# @param [String] script The string consisting of the script itself
1054+
# @param [String] type The name of the script type.
1055+
# Defaults to 'webdriverio'. Depends on server implementation which type is supported.
1056+
# @param [Integer] timeout_ms The number of `ms` Appium should wait for the script to finish
1057+
# before killing it due to timeout.
1058+
#
1059+
# @return [Appium::Core::Base::Device::ExecuteDriver::Result] The script result parsed by
1060+
# Appium::Core::Base::Device::ExecuteDriver::Result.
1061+
#
1062+
# @raise [::Selenium::WebDriver::Error::UnknownError] If something error happens in the script.
1063+
# It has the original message.
1064+
#
1065+
# @example
1066+
# script = <<~SCRIPT
1067+
# const status = await driver.status();
1068+
# console.warn('warning message');
1069+
# return [status];
1070+
# SCRIPT
1071+
# r = @@driver.execute_driver(script: script, type: 'webdriverio', timeout: 10_000)
1072+
# r #=> An instance of Appium::Core::Base::Device::ExecuteDriver::Result
1073+
# r.result #=> The `result` key part as the result of the script
1074+
# r.logs #=> The `logs` key part as `{'log' => [], 'warn' => [], 'error' => []}`
1075+
#
1076+
def execute_driver(script: '', type: 'webdriverio', timeout_ms: nil)
1077+
@bridge.execute_driver(script: script, type: type, timeout_ms: timeout_ms)
1078+
end
1079+
1080+
# Convert vanilla element response to ::Selenium::WebDriver::Element
1081+
#
1082+
# @param [Hash] id The id which can get as a response from server
1083+
# @return [::Selenium::WebDriver::Element]
1084+
#
1085+
# @example
1086+
# response = {"element-6066-11e4-a52e-4f735466cecf"=>"xxxx", "ELEMENT"=>"xxxx"}
1087+
# ele = @driver.convert_to_element(response) #=> ::Selenium::WebDriver::Element
1088+
# ele.rect #=> Can get the rect of the element
1089+
#
1090+
def convert_to_element(id)
1091+
@bridge.convert_to_element id
1092+
end
10451093
end # class Driver
10461094
end # class Base
10471095
end # module Core

lib/appium_lib_core/common/command/common.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ module Commands
6464
stop_recording_screen: [:post, 'session/:session_id/appium/stop_recording_screen'],
6565
start_recording_screen: [:post, 'session/:session_id/appium/start_recording_screen'],
6666
compare_images: [:post, 'session/:session_id/appium/compare_images'],
67-
is_keyboard_shown: [:get, 'session/:session_id/appium/device/is_keyboard_shown']
67+
is_keyboard_shown: [:get, 'session/:session_id/appium/device/is_keyboard_shown'],
68+
execute_driver: [:post, 'session/:session_id/appium/execute_driver']
6869
}.freeze
6970

7071
COMMAND_ANDROID = {
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# frozen_string_literal: true
2+
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
module Appium
16+
module Core
17+
class Base
18+
module Device
19+
module ExecuteDriver
20+
class Result
21+
attr_reader :result, :logs
22+
23+
def initialize(response)
24+
@result = response['result']
25+
@logs = response['logs']
26+
end
27+
end
28+
29+
def execute_driver(script: '', type: 'webdriverio', timeout_ms: nil)
30+
option = { script: script, type: type }
31+
32+
option[:timeout] = timeout_ms if timeout_ms
33+
34+
response = execute :execute_driver, {}, option
35+
Result.new(response)
36+
end
37+
end # module Execute
38+
end # module Device
39+
end # class Base
40+
end # module Core
41+
end # module Appium

lib/appium_lib_core/device.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ def extended(_mod)
3939
:app_state,
4040
:stop_recording_screen, :stop_and_save_recording_screen,
4141
:shake, :device_time,
42-
:touch_actions, :multi_touch
42+
:touch_actions, :multi_touch,
43+
:execute_driver
4344
].each(&method(:delegate_from_appium_driver))
4445
end
4546

test/functional/ios/driver_test.rb

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,6 @@ def test_click_back
7272

7373
# @since Appium 1.14.0
7474
def test_default_keyboard_pref
75-
skip 'til WDA 0.0.6 will be released'
76-
7775
bundle_id = @@driver.session_capabilities['CFBundleIdentifier']
7876
begin
7977
@@driver.activate_app('com.apple.Preferences')
@@ -89,6 +87,47 @@ def test_default_keyboard_pref
8987
assert_equal '0', switches_status['Predictive']
9088
end
9189

90+
# @since Appium 1.14.0
91+
def test_batch
92+
script = <<-SCRIPT
93+
const status = await driver.status();
94+
console.warn('warning message');
95+
return [status];
96+
SCRIPT
97+
98+
r = @@driver.execute_driver(script: script, type: 'webdriverio', timeout_ms: 10_000)
99+
assert(r.result.first['build'])
100+
assert('warning message', r.logs['warn'].first)
101+
end
102+
103+
# @since Appium 1.14.0
104+
def test_batch_only_return
105+
script = <<-SCRIPT
106+
SCRIPT
107+
108+
r = @@driver.execute_driver(script: script, type: 'webdriverio')
109+
assert(r.result.nil?)
110+
assert([], r.logs['warn'])
111+
end
112+
113+
# @since Appium 1.14.0
114+
def test_batch_combination_ruby_script
115+
script = <<-SCRIPT
116+
console.warn('warning message');
117+
const element = await driver.findElement('accessibility id', 'Buttons');
118+
const rect = await driver.getElementRect(element.ELEMENT);
119+
return [element, rect];
120+
SCRIPT
121+
122+
r = @@driver.execute_driver(script: script)
123+
ele = @@driver.convert_to_element(r.result.first)
124+
rect = ele.rect
125+
assert_equal(rect.x, r.result[1]['x'])
126+
assert_equal(rect.y, r.result[1]['y'])
127+
assert_equal(rect.width, r.result[1]['width'])
128+
assert_equal(rect.height, r.result[1]['height'])
129+
end
130+
92131
# TODO: call @driver.quit after tests
93132
end
94133
end

0 commit comments

Comments
 (0)