appium_lib_core 1.7.2 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -0
  3. data/CHANGELOG.md +11 -0
  4. data/lib/appium_lib_core/android/device/clipboard.rb +4 -4
  5. data/lib/appium_lib_core/android/device/screen.rb +1 -1
  6. data/lib/appium_lib_core/android/uiautomator2/device/battery.rb +2 -2
  7. data/lib/appium_lib_core/common/base.rb +17 -0
  8. data/lib/appium_lib_core/common/base/bridge.rb +1 -0
  9. data/lib/appium_lib_core/common/base/bridge/mjsonwp.rb +15 -0
  10. data/lib/appium_lib_core/common/base/bridge/w3c.rb +19 -0
  11. data/lib/appium_lib_core/common/base/driver.rb +599 -1
  12. data/lib/appium_lib_core/common/base/screenshot.rb +18 -0
  13. data/lib/appium_lib_core/common/device/app_management.rb +87 -0
  14. data/lib/appium_lib_core/common/device/app_state.rb +30 -0
  15. data/lib/appium_lib_core/common/device/battery_status.rb +25 -0
  16. data/lib/appium_lib_core/common/device/clipboard_content_type.rb +11 -0
  17. data/lib/appium_lib_core/common/device/context.rb +38 -0
  18. data/lib/appium_lib_core/common/device/device.rb +19 -0
  19. data/lib/appium_lib_core/common/device/device_lock.rb +22 -0
  20. data/lib/appium_lib_core/common/device/file_management.rb +26 -0
  21. data/lib/appium_lib_core/common/device/image_comparison.rb +168 -0
  22. data/lib/appium_lib_core/common/device/ime_actions.rb +29 -0
  23. data/lib/appium_lib_core/common/device/keyboard.rb +22 -0
  24. data/lib/appium_lib_core/common/device/keyevent.rb +38 -0
  25. data/lib/appium_lib_core/common/device/screen_record.rb +54 -0
  26. data/lib/appium_lib_core/common/device/setting.rb +17 -0
  27. data/lib/appium_lib_core/common/device/touch_actions.rb +21 -0
  28. data/lib/appium_lib_core/common/device/value.rb +19 -0
  29. data/lib/appium_lib_core/device.rb +24 -547
  30. data/lib/appium_lib_core/driver.rb +14 -9
  31. data/lib/appium_lib_core/element/image.rb +1 -1
  32. data/lib/appium_lib_core/ios/device/clipboard.rb +4 -4
  33. data/lib/appium_lib_core/ios/xcuitest/device/battery.rb +2 -2
  34. data/lib/appium_lib_core/ios/xcuitest/device/performance.rb +1 -3
  35. data/lib/appium_lib_core/ios/xcuitest/device/screen.rb +1 -1
  36. data/lib/appium_lib_core/ios_xcuitest.rb +0 -2
  37. data/lib/appium_lib_core/version.rb +2 -2
  38. data/release_notes.md +10 -0
  39. metadata +18 -17
  40. data/lib/appium_lib_core/device/app_management.rb +0 -113
  41. data/lib/appium_lib_core/device/app_state.rb +0 -32
  42. data/lib/appium_lib_core/device/battery_status.rb +0 -23
  43. data/lib/appium_lib_core/device/clipboard_content_type.rb +0 -9
  44. data/lib/appium_lib_core/device/context.rb +0 -48
  45. data/lib/appium_lib_core/device/device_lock.rb +0 -28
  46. data/lib/appium_lib_core/device/file_management.rb +0 -32
  47. data/lib/appium_lib_core/device/image_comparison.rb +0 -178
  48. data/lib/appium_lib_core/device/ime_actions.rb +0 -43
  49. data/lib/appium_lib_core/device/keyboard.rb +0 -26
  50. data/lib/appium_lib_core/device/keyevent.rb +0 -44
  51. data/lib/appium_lib_core/device/screen_record.rb +0 -56
  52. data/lib/appium_lib_core/device/setting.rb +0 -21
  53. data/lib/appium_lib_core/device/touch_actions.rb +0 -22
  54. data/lib/appium_lib_core/device/value.rb +0 -23
@@ -77,6 +77,24 @@ module Appium
77
77
  raise Core::Error::UnsupportedOperationError, "unsupported format: #{format.inspect}"
78
78
  end
79
79
  end
80
+
81
+ # @since 1.3.4
82
+ # @!method save_viewport_screenshot
83
+ # Save screenshot except for status bar while `@driver.save_screenshot` save entire screen.
84
+ #
85
+ # @example
86
+ #
87
+ # @driver.save_viewport_screenshot 'path/to/save.png' #=> Get the File instance of viewport_screenshot
88
+ #
89
+ def save_viewport_screenshot(png_path)
90
+ extension = File.extname(png_path).downcase
91
+ if extension != '.png'
92
+ ::Appium::Logger.warn 'name used for saved screenshot does not match file type. '\
93
+ 'It should end with .png extension'
94
+ end
95
+ viewport_screenshot_encode64 = bridge.take_viewport_screenshot
96
+ File.open(png_path, 'wb') { |f| f << viewport_screenshot_encode64.unpack('m')[0] }
97
+ end
80
98
  end
81
99
  end
82
100
  end
@@ -0,0 +1,87 @@
1
+ module Appium
2
+ module Core
3
+ class Base
4
+ module Device
5
+ module AppManagement
6
+ def launch_app
7
+ execute :launch_app
8
+ end
9
+
10
+ def close_app
11
+ execute :close_app
12
+ end
13
+
14
+ def reset
15
+ execute :reset
16
+ end
17
+
18
+ def app_strings(language = nil)
19
+ opts = language ? { language: language } : {}
20
+ execute :app_strings, {}, opts
21
+ end
22
+
23
+ def background_app(duration = 0)
24
+ execute :background_app, {}, seconds: duration
25
+ end
26
+
27
+ def install_app(path,
28
+ replace: nil,
29
+ timeout: nil,
30
+ allow_test_packages: nil,
31
+ use_sdcard: nil,
32
+ grant_permissions: nil)
33
+ args = { appPath: path }
34
+
35
+ args[:options] = {} unless options?(replace, timeout, allow_test_packages, use_sdcard, grant_permissions)
36
+
37
+ args[:options][:replace] = replace unless replace.nil?
38
+ args[:options][:timeout] = timeout unless timeout.nil?
39
+ args[:options][:allowTestPackages] = allow_test_packages unless allow_test_packages.nil?
40
+ args[:options][:useSdcard] = use_sdcard unless use_sdcard.nil?
41
+ args[:options][:grantPermissions] = grant_permissions unless grant_permissions.nil?
42
+
43
+ execute :install_app, {}, args
44
+ end
45
+
46
+ def remove_app(id, keep_data: nil, timeout: nil)
47
+ # required: [['appId'], ['bundleId']]
48
+ args = { appId: id }
49
+
50
+ args[:options] = {} unless keep_data.nil? || timeout.nil?
51
+ args[:options][:keepData] = keep_data unless keep_data.nil?
52
+ args[:options][:timeout] = timeout unless timeout.nil?
53
+
54
+ execute :remove_app, {}, args
55
+ end
56
+
57
+ def app_installed?(app_id)
58
+ # required: [['appId'], ['bundleId']]
59
+ execute :app_installed?, {}, bundleId: app_id
60
+ end
61
+
62
+ def activate_app(app_id)
63
+ # required: [['appId'], ['bundleId']]
64
+ execute :activate_app, {}, bundleId: app_id
65
+ end
66
+
67
+ def terminate_app(app_id, timeout: nil)
68
+ # required: [['appId'], ['bundleId']]
69
+ #
70
+ args = { appId: app_id }
71
+
72
+ args[:options] = {} unless timeout.nil?
73
+ args[:options][:timeout] = timeout unless timeout.nil?
74
+
75
+ execute :terminate_app, {}, args
76
+ end
77
+
78
+ private
79
+
80
+ def options?(replace, timeout, allow_test_packages, use_sdcard, grant_permissions)
81
+ replace.nil? || timeout.nil? || allow_test_packages.nil? || use_sdcard.nil? || grant_permissions.nil?
82
+ end
83
+ end # module AppManagement
84
+ end # module Device
85
+ end # class Base
86
+ end # module Core
87
+ end # module Appium
@@ -0,0 +1,30 @@
1
+ module Appium
2
+ module Core
3
+ class Base
4
+ module Device
5
+ module AppState
6
+ STATUS = [
7
+ :not_installed, # 0
8
+ :not_running, # 1
9
+ :running_in_background_suspended, # 2
10
+ :running_in_background, # 3
11
+ :running_in_foreground # 4
12
+ ].freeze
13
+
14
+ def app_state(app_id)
15
+ # required: [['appId'], ['bundleId']]
16
+ response = execute :app_state, {}, appId: app_id
17
+
18
+ case response
19
+ when 0, 1, 2, 3, 4
20
+ STATUS[response]
21
+ else
22
+ ::Appium::Logger.debug("Unexpected status in app_state: #{response}")
23
+ response
24
+ end
25
+ end
26
+ end # module AppState
27
+ end # module Device
28
+ end # class Base
29
+ end # module Core
30
+ end # module Appium
@@ -0,0 +1,25 @@
1
+ module Appium
2
+ module Core
3
+ class Base
4
+ module Device
5
+ module BatteryStatus
6
+ ANDROID = [
7
+ :undefined, # 0, dummy
8
+ :unknown, # 1
9
+ :charging, # 2
10
+ :discharging, # 3
11
+ :not_charging, # 4
12
+ :full # 5
13
+ ].freeze
14
+
15
+ IOS = [
16
+ :unknown, # 0
17
+ :unplugged, # 1
18
+ :charging, # 2
19
+ :full # 3
20
+ ].freeze
21
+ end # module BatteryStatus
22
+ end # module Device
23
+ end # class Base
24
+ end # module Core
25
+ end # module Appium
@@ -0,0 +1,11 @@
1
+ module Appium
2
+ module Core
3
+ class Base
4
+ module Device
5
+ module Clipboard
6
+ CONTENT_TYPE = [:plaintext, :image, :url].freeze
7
+ end
8
+ end # module Clipboard
9
+ end # class Base
10
+ end # module Core
11
+ end # module Appium
@@ -0,0 +1,38 @@
1
+ module Appium
2
+ module Core
3
+ class Base
4
+ module Device
5
+ module Context
6
+ def within_context(context)
7
+ existing_context = current_context
8
+ set_context context
9
+ if block_given?
10
+ result = yield
11
+ set_context existing_context
12
+ result
13
+ else
14
+ set_context existing_context
15
+ end
16
+ end
17
+
18
+ def switch_to_default_context
19
+ set_context nil
20
+ end
21
+
22
+ def current_context
23
+ execute :current_context
24
+ end
25
+
26
+ def available_contexts
27
+ # return empty array instead of nil on failure
28
+ execute(:available_contexts, {}) || []
29
+ end
30
+
31
+ def set_context(context = null)
32
+ execute :set_context, {}, name: context
33
+ end
34
+ end # module ImeActions
35
+ end # module Device
36
+ end # class Base
37
+ end # module Core
38
+ end # module Appium
@@ -0,0 +1,19 @@
1
+ module Appium
2
+ module Core
3
+ class Base
4
+ module Device
5
+ module Device
6
+ def shake
7
+ execute :shake
8
+ end
9
+
10
+ def device_time(format = nil)
11
+ arg = {}
12
+ arg[:format] = format unless format.nil?
13
+ execute :device_time, {}, arg
14
+ end
15
+ end # module Device
16
+ end # module Device
17
+ end # class Base
18
+ end # module Core
19
+ end # module Appium
@@ -0,0 +1,22 @@
1
+ module Appium
2
+ module Core
3
+ class Base
4
+ module Device
5
+ module DeviceLock
6
+ def lock(duration = nil)
7
+ opts = duration ? { seconds: duration } : {}
8
+ execute :lock, {}, opts
9
+ end
10
+
11
+ def device_locked?
12
+ execute :device_locked?
13
+ end
14
+
15
+ def unlock
16
+ execute :unlock
17
+ end
18
+ end # module DeviceLock
19
+ end # module Device
20
+ end # class Base
21
+ end # module Core
22
+ end # module Appium
@@ -0,0 +1,26 @@
1
+ require 'base64'
2
+
3
+ module Appium
4
+ module Core
5
+ class Base
6
+ module Device
7
+ module FileManagement
8
+ def push_file(path, filedata)
9
+ encoded_data = Base64.encode64 filedata
10
+ execute :push_file, {}, path: path, data: encoded_data
11
+ end
12
+
13
+ def pull_file(path)
14
+ data = execute :pull_file, {}, path: path
15
+ Base64.decode64 data
16
+ end
17
+
18
+ def pull_folder(path)
19
+ data = execute :pull_folder, {}, path: path
20
+ Base64.decode64 data
21
+ end
22
+ end # module FileManagement
23
+ end # module Device
24
+ end # class Base
25
+ end # module Core
26
+ end # module Appium
@@ -0,0 +1,168 @@
1
+ require 'base64'
2
+
3
+ module Appium
4
+ module Core
5
+ class Base
6
+ module Device
7
+ module ImageComparison
8
+ MODE = [:matchFeatures, :getSimilarity, :matchTemplate].freeze
9
+
10
+ MATCH_FEATURES = {
11
+ detector_name: %w(AKAZE AGAST BRISK FAST GFTT KAZE MSER SIFT ORB),
12
+ match_func: %w(FlannBased BruteForce BruteForceL1 BruteForceHamming BruteForceHammingLut BruteForceSL2),
13
+ goodMatchesFactor: nil, # Integer
14
+ visualize: [true, false]
15
+ }.freeze
16
+
17
+ MATCH_TEMPLATE = {
18
+ visualize: [true, false]
19
+ }.freeze
20
+
21
+ GET_SIMILARITY = {
22
+ visualize: [true, false]
23
+ }.freeze
24
+
25
+ # @!method match_images_features(first_image:, second_image:, detector_name: 'ORB',
26
+ # match_func: 'BruteForce', good_matches_factor: 100, visualize: false)
27
+ # Performs images matching by features with default options. Read https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_feature2d/py_matcher/py_matcher.html
28
+ # for more details on this topic.
29
+ #
30
+ # @param [String] first_image An image data. All image formats, that OpenCV library itself accepts, are supported.
31
+ # @param [String] second_image An image data. All image formats, that OpenCV library itself accepts, are supported.
32
+ # @param [String] detector_name Sets the detector name for features matching
33
+ # algorithm. Some of these detectors (FAST, AGAST, GFTT, FAST, SIFT and MSER) are
34
+ # not available in the default OpenCV installation and have to be enabled manually
35
+ # before library compilation. The default detector name is 'ORB'.
36
+ # @param [String] match_func The name of the matching function. The default one is 'BruteForce'.
37
+ # @param [String] good_matches_factor The maximum count of "good" matches (e. g. with minimal distances).
38
+ # The default one is nil.
39
+ # @param [Bool] visualise Makes the endpoint to return an image, which contains the visualized result of
40
+ # the corresponding picture matching operation. This option is disabled by default.
41
+ #
42
+ # @example
43
+ # @driver.match_images_features first_image: "image data 1", second_image: "image data 2"
44
+ #
45
+ # visual = @@driver.match_images_features first_image: image1, second_image: image2, visualize: true
46
+ # File.write 'match_images_visual.png', Base64.decode64(visual['visualization']) # if the image is PNG
47
+ #
48
+
49
+ # @!method find_image_occurrence(full_image:, partial_image:, visualize: false, threshold: nil)
50
+ # Performs images matching by template to find possible occurrence of the partial image
51
+ # in the full image with default options. Read https://docs.opencv.org/2.4/doc/tutorials/imgproc/histograms/template_matching/template_matching.html
52
+ # for more details on this topic.
53
+ #
54
+ # @param [String] full_image: A full image data.
55
+ # @param [String] partial_image: A partial image data. All image formats, that OpenCV library itself accepts,
56
+ # are supported.
57
+ # @param [Bool] visualise: Makes the endpoint to return an image, which contains the visualized result of
58
+ # the corresponding picture matching operation. This option is disabled by default.
59
+ # @param [Float] threshold: [0.5] At what normalized threshold to reject
60
+ #
61
+ # @example
62
+ # @driver.find_image_occurrence full_image: "image data 1", partial_image: "image data 2"
63
+ #
64
+ # visual = @@driver.find_image_occurrence full_image: image1, partial_image: image2, visualize: true
65
+ # File.write 'find_result_visual.png', Base64.decode64(visual['visualization']) # if the image is PNG
66
+ #
67
+
68
+ # @!method get_images_similarity(first_image:, second_image:, detector_name: 'ORB', visualize: false)
69
+ # Performs images matching to calculate the similarity score between them
70
+ # with default options. The flow there is similar to the one used in `find_image_occurrence`
71
+ # but it is mandatory that both images are of equal size.
72
+ #
73
+ # @param [String] first_image: An image data. All image formats, that OpenCV library itself accepts, are supported.
74
+ # @param [String] second_image: An image data. All image formats, that OpenCV library itself accepts, are supported.
75
+ # @param [Bool] visualise: Makes the endpoint to return an image, which contains the visualized result of
76
+ # the corresponding picture matching operation. This option is disabled by default.
77
+ #
78
+ # @example
79
+ # @driver.get_images_similarity first_image: "image data 1", second_image: "image data 2"
80
+ #
81
+ # visual = @@driver.get_images_similarity first_image: image1, second_image: image2, visualize: true
82
+ # File.write 'images_similarity_visual.png', Base64.decode64(visual['visualization']) # if the image is PNG
83
+ #
84
+
85
+ # @!method compare_images(mode:, first_image:, second_image:, options:)
86
+ #
87
+ # Performs images comparison using OpenCV framework features.
88
+ # It is expected that both OpenCV framework and opencv4nodejs
89
+ # module are installed on the machine where Appium server is running.
90
+ #
91
+ # @param [Symbol] mode: One of possible comparison modes: `:matchFeatures`, `:getSimilarity`, `:matchTemplate`.
92
+ # `:matchFeatures is by default.
93
+ # @param [String] first_image: An image data. All image formats, that OpenCV library itself accepts, are supported.
94
+ # @param [String] second_image: An image data. All image formats, that OpenCV library itself accepts, are supported.
95
+ # @param [Hash] options: The content of this dictionary depends on the actual `mode` value.
96
+ # See the documentation on `appium-support` module for more details.
97
+ # @returns [Hash] The content of the resulting dictionary depends on the actual `mode` and `options` values.
98
+ # See the documentation on `appium-support` module for more details.
99
+ #
100
+
101
+ ####
102
+ ## class << self
103
+ ####
104
+
105
+ def match_images_features(first_image:,
106
+ second_image:,
107
+ detector_name: 'ORB',
108
+ match_func: 'BruteForce',
109
+ good_matches_factor: nil,
110
+ visualize: false)
111
+ unless MATCH_FEATURES[:detector_name].member?(detector_name.to_s)
112
+ raise "detector_name should be #{MATCH_FEATURES[:detector_name]}"
113
+ end
114
+ unless MATCH_FEATURES[:match_func].member?(match_func.to_s)
115
+ raise "match_func should be #{MATCH_FEATURES[:match_func]}"
116
+ end
117
+ unless MATCH_FEATURES[:visualize].member?(visualize)
118
+ raise "visualize should be #{MATCH_FEATURES[:visualize]}"
119
+ end
120
+
121
+ options = {}
122
+ options[:detectorName] = detector_name.to_s.upcase
123
+ options[:matchFunc] = match_func.to_s
124
+ options[:goodMatchesFactor] = good_matches_factor.to_i unless good_matches_factor.nil?
125
+ options[:visualize] = visualize
126
+
127
+ compare_images(mode: :matchFeatures, first_image: first_image, second_image: second_image, options: options)
128
+ end
129
+
130
+ def find_image_occurrence(full_image:, partial_image:, visualize: false, threshold: nil)
131
+ unless MATCH_TEMPLATE[:visualize].member?(visualize)
132
+ raise "visualize should be #{MATCH_TEMPLATE[:visualize]}"
133
+ end
134
+
135
+ options = {}
136
+ options[:visualize] = visualize
137
+ options[:threshold] = threshold unless threshold.nil?
138
+
139
+ compare_images(mode: :matchTemplate, first_image: full_image, second_image: partial_image, options: options)
140
+ end
141
+
142
+ def get_images_similarity(first_image:, second_image:, visualize: false)
143
+ unless GET_SIMILARITY[:visualize].member?(visualize)
144
+ raise "visualize should be #{GET_SIMILARITY[:visualize]}"
145
+ end
146
+
147
+ options = {}
148
+ options[:visualize] = visualize
149
+
150
+ compare_images(mode: :getSimilarity, first_image: first_image, second_image: second_image, options: options)
151
+ end
152
+
153
+ def compare_images(mode: :matchFeatures, first_image:, second_image:, options: nil)
154
+ raise "content_type should be #{MODE}" unless MODE.member?(mode)
155
+
156
+ params = {}
157
+ params[:mode] = mode
158
+ params[:firstImage] = Base64.encode64 first_image
159
+ params[:secondImage] = Base64.encode64 second_image
160
+ params[:options] = options if options
161
+
162
+ execute(:compare_images, {}, params)
163
+ end
164
+ end # module ImageComparison
165
+ end # module Device
166
+ end # class Base
167
+ end # module Core
168
+ end # module Appium