calabash 1.2.1 → 1.9.9.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +39 -0
  3. data/LICENSE +204 -21
  4. data/README.md +36 -6
  5. data/VERSIONING.md +16 -0
  6. data/bin/calabash +95 -0
  7. data/lib/calabash.rb +185 -1
  8. data/lib/calabash/android.rb +64 -0
  9. data/lib/calabash/android/adb.rb +277 -0
  10. data/lib/calabash/android/application.rb +110 -0
  11. data/lib/calabash/android/build.rb +12 -0
  12. data/lib/calabash/android/build/application.rb +13 -0
  13. data/lib/calabash/android/build/build_error.rb +11 -0
  14. data/lib/calabash/android/build/builder.rb +119 -0
  15. data/lib/calabash/android/build/java_keystore.rb +177 -0
  16. data/lib/calabash/android/build/resigner.rb +56 -0
  17. data/lib/calabash/android/build/test_server.rb +27 -0
  18. data/lib/calabash/android/console_helpers.rb +44 -0
  19. data/lib/calabash/android/cucumber.rb +3 -0
  20. data/lib/calabash/android/device.rb +965 -0
  21. data/lib/calabash/android/environment.rb +470 -0
  22. data/lib/calabash/android/gestures.rb +369 -0
  23. data/lib/calabash/android/interactions.rb +45 -0
  24. data/lib/calabash/android/lib/.irbrc +55 -0
  25. data/lib/calabash/android/lib/AndroidManifest.xml +51 -0
  26. data/lib/calabash/android/lib/TestServer.apk +0 -0
  27. data/lib/calabash/android/lib/calmd5/arm64-v8a/calmd5 +0 -0
  28. data/lib/calabash/android/lib/calmd5/arm64-v8a/calmd5-pie +0 -0
  29. data/lib/calabash/android/lib/calmd5/armeabi-v7a/calmd5 +0 -0
  30. data/lib/calabash/android/lib/calmd5/armeabi-v7a/calmd5-pie +0 -0
  31. data/lib/calabash/android/lib/calmd5/armeabi/calmd5 +0 -0
  32. data/lib/calabash/android/lib/calmd5/armeabi/calmd5-pie +0 -0
  33. data/lib/calabash/android/lib/calmd5/mips/calmd5 +0 -0
  34. data/lib/calabash/android/lib/calmd5/mips/calmd5-pie +0 -0
  35. data/lib/calabash/android/lib/calmd5/mips64/calmd5 +0 -0
  36. data/lib/calabash/android/lib/calmd5/mips64/calmd5-pie +0 -0
  37. data/lib/calabash/android/lib/calmd5/x86/calmd5 +0 -0
  38. data/lib/calabash/android/lib/calmd5/x86/calmd5-pie +0 -0
  39. data/lib/calabash/android/lib/calmd5/x86_64/calmd5 +0 -0
  40. data/lib/calabash/android/lib/calmd5/x86_64/calmd5-pie +0 -0
  41. data/lib/calabash/android/lib/screenshot_taker.jar +0 -0
  42. data/lib/calabash/android/life_cycle.rb +37 -0
  43. data/lib/calabash/android/orientation.rb +30 -0
  44. data/lib/calabash/android/physical_buttons.rb +39 -0
  45. data/lib/calabash/android/screenshot.rb +9 -0
  46. data/lib/calabash/android/scroll.rb +5 -0
  47. data/lib/calabash/android/server.rb +10 -0
  48. data/lib/calabash/android/text.rb +54 -0
  49. data/lib/calabash/application.rb +74 -0
  50. data/lib/calabash/cli.rb +12 -0
  51. data/lib/calabash/cli/build.rb +33 -0
  52. data/lib/calabash/cli/console.rb +90 -0
  53. data/lib/calabash/cli/generate.rb +110 -0
  54. data/lib/calabash/cli/helpers.rb +130 -0
  55. data/lib/calabash/cli/resign.rb +33 -0
  56. data/lib/calabash/cli/run.rb +99 -0
  57. data/lib/calabash/cli/setup_keystore.rb +39 -0
  58. data/lib/calabash/color.rb +32 -0
  59. data/lib/calabash/console_helpers.rb +90 -0
  60. data/lib/calabash/defaults.rb +56 -0
  61. data/lib/calabash/device.rb +401 -0
  62. data/lib/calabash/environment.rb +75 -0
  63. data/lib/calabash/gestures.rb +384 -0
  64. data/lib/calabash/http.rb +8 -0
  65. data/lib/calabash/http/error.rb +15 -0
  66. data/lib/calabash/http/request.rb +42 -0
  67. data/lib/calabash/http/retriable_client.rb +156 -0
  68. data/lib/calabash/interactions.rb +105 -0
  69. data/lib/calabash/ios.rb +37 -0
  70. data/lib/calabash/ios/application.rb +119 -0
  71. data/lib/calabash/ios/conditions.rb +79 -0
  72. data/lib/calabash/ios/console_helpers.rb +72 -0
  73. data/lib/calabash/ios/device.rb +24 -0
  74. data/lib/calabash/ios/device/device_implementation.rb +779 -0
  75. data/lib/calabash/ios/device/gestures_mixin.rb +167 -0
  76. data/lib/calabash/ios/device/keyboard_mixin.rb +133 -0
  77. data/lib/calabash/ios/device/physical_device_mixin.rb +266 -0
  78. data/lib/calabash/ios/device/rotation_mixin.rb +124 -0
  79. data/lib/calabash/ios/device/routes/backdoor_route_mixin.rb +86 -0
  80. data/lib/calabash/ios/device/routes/condition_route_mixin.rb +62 -0
  81. data/lib/calabash/ios/device/routes/error.rb +8 -0
  82. data/lib/calabash/ios/device/routes/handle_route_mixin.rb +102 -0
  83. data/lib/calabash/ios/device/routes/map_route_mixin.rb +38 -0
  84. data/lib/calabash/ios/device/routes/playback_route_mixin.rb +70 -0
  85. data/lib/calabash/ios/device/routes/response_parser.rb +48 -0
  86. data/lib/calabash/ios/device/routes/uia_route_mixin.rb +238 -0
  87. data/lib/calabash/ios/device/runtime_attributes.rb +184 -0
  88. data/lib/calabash/ios/device/status_bar_mixin.rb +17 -0
  89. data/lib/calabash/ios/device/text_mixin.rb +19 -0
  90. data/lib/calabash/ios/device/uia_keyboard_mixin.rb +188 -0
  91. data/lib/calabash/ios/device/uia_mixin.rb +12 -0
  92. data/lib/calabash/ios/environment.rb +41 -0
  93. data/lib/calabash/ios/interactions.rb +10 -0
  94. data/lib/calabash/ios/lib/.irbrc +55 -0
  95. data/lib/calabash/ios/lib/recordings/rotate_left_home_down_ipad.base64 +2 -0
  96. data/lib/calabash/ios/lib/recordings/rotate_left_home_down_iphone.base64 +2 -0
  97. data/lib/calabash/ios/lib/recordings/rotate_left_home_left_ipad.base64 +2 -0
  98. data/lib/calabash/ios/lib/recordings/rotate_left_home_left_iphone.base64 +2 -0
  99. data/lib/calabash/ios/lib/recordings/rotate_left_home_right_ipad.base64 +2 -0
  100. data/lib/calabash/ios/lib/recordings/rotate_left_home_right_iphone.base64 +2 -0
  101. data/lib/calabash/ios/lib/recordings/rotate_left_home_up_ipad.base64 +2 -0
  102. data/lib/calabash/ios/lib/recordings/rotate_left_home_up_iphone.base64 +2 -0
  103. data/lib/calabash/ios/lib/recordings/rotate_right_home_down_ipad.base64 +2 -0
  104. data/lib/calabash/ios/lib/recordings/rotate_right_home_down_iphone.base64 +2 -0
  105. data/lib/calabash/ios/lib/recordings/rotate_right_home_left_ipad.base64 +2 -0
  106. data/lib/calabash/ios/lib/recordings/rotate_right_home_left_iphone.base64 +2 -0
  107. data/lib/calabash/ios/lib/recordings/rotate_right_home_right_ipad.base64 +2 -0
  108. data/lib/calabash/ios/lib/recordings/rotate_right_home_right_iphone.base64 +2 -0
  109. data/lib/calabash/ios/lib/recordings/rotate_right_home_up_ipad.base64 +2 -0
  110. data/lib/calabash/ios/lib/recordings/rotate_right_home_up_iphone.base64 +2 -0
  111. data/lib/calabash/ios/orientation.rb +117 -0
  112. data/lib/calabash/ios/scroll.rb +504 -0
  113. data/lib/calabash/ios/server.rb +73 -0
  114. data/lib/calabash/ios/text.rb +248 -0
  115. data/lib/calabash/ios/uia.rb +24 -0
  116. data/lib/calabash/lib/skeleton/config/cucumber.yml +6 -0
  117. data/lib/calabash/lib/skeleton/features/sample.feature +5 -0
  118. data/lib/calabash/lib/skeleton/features/step_definitions/calabash_steps.rb +29 -0
  119. data/lib/calabash/lib/skeleton/features/support/env.rb +54 -0
  120. data/lib/calabash/lib/skeleton/features/support/hooks.rb +83 -0
  121. data/lib/calabash/life_cycle.rb +111 -0
  122. data/lib/calabash/location.rb +51 -0
  123. data/lib/calabash/logger.rb +87 -0
  124. data/lib/calabash/orientation.rb +84 -0
  125. data/lib/calabash/page.rb +35 -0
  126. data/lib/calabash/patch.rb +14 -0
  127. data/lib/calabash/patch/array.rb +16 -0
  128. data/lib/calabash/patch/run_loop.rb +90 -0
  129. data/lib/calabash/query.rb +160 -0
  130. data/lib/calabash/query_result.rb +85 -0
  131. data/lib/calabash/screenshot.rb +89 -0
  132. data/lib/calabash/server.rb +16 -0
  133. data/lib/calabash/text.rb +76 -0
  134. data/lib/calabash/utility.rb +58 -0
  135. data/lib/calabash/version.rb +3 -1
  136. data/lib/calabash/wait.rb +474 -0
  137. metadata +462 -24
@@ -0,0 +1,48 @@
1
+ module Calabash
2
+ module IOS
3
+ # @!visibility private
4
+ module Routes
5
+
6
+ # @!visibility private
7
+ module ResponseParser
8
+
9
+ def parse_response_body(response)
10
+ body = response.body
11
+ begin
12
+ hash = JSON.parse(body)
13
+ rescue TypeError, JSON::ParserError => e
14
+ raise Calabash::IOS::RouteError, "Could not parse response '#{body}: #{e}'"
15
+ end
16
+
17
+ outcome = hash['outcome']
18
+
19
+ case outcome
20
+ when 'FAILURE'
21
+ reason = hash['reason']
22
+ if reason.nil? || reason.empty?
23
+ hash['reason'] = 'Server provided no reason.'
24
+ end
25
+
26
+ details = hash['details']
27
+ if details.nil? || details.empty?
28
+ hash['details'] = 'Server provided no details.'
29
+ end
30
+
31
+ when 'SUCCESS'
32
+ # Backdoor route returns a 'result' key. Grr.
33
+ # Legacy API: will be removed in Calabash iOS Server > 0.14.3
34
+ if !(hash.has_key?('results') || hash.has_key?('result'))
35
+ raise Calabash::IOS::RouteError, "Server responded with '#{outcome}'" \
36
+ "but response #{hash} does not contain 'results' key"
37
+ end
38
+ else
39
+ raise Calabash::IOS::RouteError, 'Server responded with an invalid outcome:' \
40
+ "'#{hash['outcome']}'"
41
+ end
42
+ hash
43
+ end
44
+
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,238 @@
1
+ module Calabash
2
+ module IOS
3
+ # @!visibility private
4
+ module Routes
5
+
6
+ # @!visibility private
7
+ module UIARouteMixin
8
+
9
+ require 'run_loop'
10
+ require 'edn'
11
+
12
+ def uia_route(command)
13
+ unless run_loop
14
+ if defined?(IRB)
15
+ logger.log('', :info)
16
+ logger.log(Color.red('This console is not attached to a run-loop.'), :info)
17
+ logger.log('', :info)
18
+ logger.log(Color.green('If your have not launched your app yet, launch it with:'), :info)
19
+ logger.log('', :info)
20
+ logger.log(Color.cyan('> start_app'), :info)
21
+ logger.log('', :info)
22
+ logger.log('', :info)
23
+ logger.log(Color.green('If your Calabash app is already running, ' \
24
+ "you can attach to it's run-loop:"), :info)
25
+ logger.log('', :info)
26
+ logger.log(Color.cyan('> console_attach # Attaches with the default strategy.'),
27
+ :info)
28
+ logger.log(Color.cyan('> console_attach(uia_strategy) # Attaches with a specific strategy.'),
29
+ :info)
30
+ logger.log('', :info)
31
+ logger.log('', :info)
32
+ raise 'This console is not attached a run-loop.'
33
+ else
34
+ raise 'This device does not have a connection to run-loop. Call start_app first.'
35
+ end
36
+ end
37
+
38
+ strategy = uia_strategy
39
+
40
+ case strategy
41
+ when :preferences
42
+ uia_over_http(command, 'uia')
43
+ when :shared_element
44
+ uia_over_http(command, 'uia-shared')
45
+ when :host
46
+ uia_over_host(command)
47
+ else
48
+ raise Calabash::IOS::RouteError, "Invalid :uia_strategy '#{strategy}'. Valid strategies are: '#{UIA_STRATEGIES}"
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ UIA_STRATEGIES = [:preferences, :host, :shared_element]
55
+
56
+ # Careful. The UIA route can return all manner of weird responses.
57
+ def uia_over_http(command, route)
58
+ request = make_uia_request(command, route)
59
+ response = route_post_request(request)
60
+ parsed = parse_response_body(response)
61
+ handle_uia_results(parsed['results'], command)
62
+ end
63
+
64
+ # Careful. The UIA route can return all manner of weird responses.
65
+ def uia_over_host(command)
66
+ [RunLoop.send_command(run_loop, command)]
67
+ end
68
+
69
+ # Called _after_ route_handle_response or _after_ RunLoop.send_command
70
+ def handle_uia_results(response, command)
71
+ expect_uia_results_is_array(response)
72
+
73
+ expect_uia_results_has_one_element(response)
74
+
75
+ hash = response.first
76
+
77
+ expect_uia_result_has_valid_status_key(hash, response, command)
78
+
79
+ expect_uia_result_has_value_key(hash, response, command)
80
+
81
+ status = hash['status']
82
+ value = hash['value']
83
+
84
+ if status == 'error'
85
+ raise "Executing command '#{command}'\n" \
86
+ "resulted in an error: '#{value}'"
87
+ else
88
+ handle_uia_result_with_success(value)
89
+ end
90
+ end
91
+
92
+ def expect_uia_results_is_array(response)
93
+ if !response.is_a? Array
94
+ raise "Expected '#{response}' to be an array."
95
+ end
96
+ response
97
+ end
98
+
99
+ def expect_uia_results_has_one_element(response)
100
+ if response.length != 1
101
+ raise "Expected '#{response}' to have exactly one element"
102
+ end
103
+ response
104
+ end
105
+
106
+ def expect_uia_response_element_is_hash(hash)
107
+ if !hash.is_a? Hash
108
+ raise "Expected first result of '#{hash}' to be a Hash"
109
+ end
110
+ hash
111
+ end
112
+
113
+ def expect_uia_result_has_valid_status_key(hash, response, command)
114
+ status = hash['status']
115
+
116
+ case status
117
+ when 'error', 'success'
118
+ hash
119
+ else
120
+ raise "Executing command '#{command}'\n" \
121
+ "returned an invalid status key: '#{status}'.\n" \
122
+ "Expected 'error' or 'success'.\n" \
123
+ "The raw response was '#{response}'"
124
+ end
125
+ hash
126
+ end
127
+
128
+ def expect_uia_result_has_value_key(hash, response, command)
129
+ if !hash.has_key? 'value'
130
+ raise "Executing command '#{command}'\n" \
131
+ "returned a value with no 'value' key.\n" \
132
+ "Then raw response was '#{response}'"
133
+ end
134
+ hash
135
+ end
136
+
137
+ def handle_uia_result_with_success(value)
138
+ if value.is_a? Array
139
+ value
140
+ elsif value == ':nil'
141
+ [nil]
142
+ else
143
+ [value]
144
+ end
145
+ end
146
+
147
+ def make_uia_parameters(command)
148
+ {
149
+ :command => command
150
+ }
151
+ end
152
+
153
+ def make_uia_request(command, route)
154
+ parameters = make_uia_parameters(command)
155
+ begin
156
+ Calabash::HTTP::Request.request(route, parameters)
157
+ rescue => e
158
+ raise Calabash::IOS::RouteError, e
159
+ end
160
+ end
161
+
162
+ def uia_serialize_and_call(uia_command, *query_args)
163
+ command = uia_serialize_command(uia_command, *query_args)
164
+ result = uia_route(command)
165
+ result.first
166
+ end
167
+
168
+ # @todo Verify this is the correct way to escape '\n in string
169
+ def uia_escape_string(string)
170
+ Calabash::Text.escape_single_quotes(string).gsub("\n", "\\\\n")
171
+ end
172
+
173
+ def uia_serialize_argument(part)
174
+ if part.is_a?(String)
175
+ "'#{uia_escape_string(part)}'"
176
+ else
177
+ "'#{uia_escape_string(part.to_edn)}'"
178
+ end
179
+ end
180
+
181
+ def uia_serialize_arguments(argument_array)
182
+ argument_array.map do |part|
183
+ uia_serialize_argument(part)
184
+ end
185
+ end
186
+
187
+ def uia_serialize_command(uia_command, *query_args)
188
+ args = uia_serialize_arguments(query_args)
189
+ %Q[uia.#{uia_command}(#{args.join(', ')})]
190
+ end
191
+
192
+ # @todo Move to a translate mixin (or helper)
193
+ # @todo No unit tests for this yet!
194
+ def uia_center_of_view(view_hash)
195
+ rect = view_hash['rect']
196
+
197
+ # Why would the view hash not have a rect?
198
+ unless rect
199
+ raise "Expected '#{view_hash}' to have a 'rect' key"
200
+ end
201
+ {:x => rect['center_x'], :y => rect['center_y']}
202
+ end
203
+
204
+ # @todo Move to a translate mixin (or helper)
205
+ # def point_from(query_result, options={})
206
+ # offset_x = 0
207
+ # offset_y = 0
208
+ # if options[:offset]
209
+ # offset_x += options[:offset][:x] || 0
210
+ # offset_y += options[:offset][:y] || 0
211
+ # end
212
+ # x = offset_x
213
+ # y = offset_y
214
+ # rect = query_result['rect'] || query_result[:rect]
215
+ # if rect
216
+ # x += rect['center_x'] || rect[:center_x] || rect[:x] || 0
217
+ # y += rect['center_y'] || rect[:center_y] || rect[:y] || 0
218
+ # else
219
+ # x += query_result['center_x'] || query_result[:center_x] || query_result[:x] || 0
220
+ # y += query_result['center_y'] || query_result[:center_y] || query_result[:y] || 0
221
+ # end
222
+ #
223
+ # {:x => x, :y => y}
224
+ # end
225
+
226
+ # @todo Is this worth keeping?
227
+ # def uia_result(s)
228
+ # query_result = s.first
229
+ # if query_result['status'] == 'success'
230
+ # query_result['value']
231
+ # else
232
+ # query_result['status']
233
+ # end
234
+ # end
235
+ end
236
+ end
237
+ end
238
+ end
@@ -0,0 +1,184 @@
1
+ module Calabash
2
+ module IOS
3
+
4
+ # @!visibility private
5
+ # This class provides information about the device under test that can
6
+ # only be obtained at run time.
7
+ class RuntimeAttributes
8
+
9
+ require 'run_loop'
10
+
11
+ # @!visibility private
12
+ # Creates a new instance of DeviceRuntimeInfo.
13
+ # @param [Hash] runtime_info The result of calling the version route on
14
+ # on the server
15
+ # @return [Calabash::IOS::RuntimeAttributes] A new info object.
16
+ def initialize(runtime_info)
17
+ @runtime_info = runtime_info
18
+ end
19
+
20
+ # @!visibility private
21
+ # The device family of this device.
22
+ #
23
+ # @example
24
+ # # will be one of
25
+ # iPhone
26
+ # iPod
27
+ # iPad
28
+ #
29
+ # @return [String] the device family
30
+ def device_family
31
+ @device_family ||= lambda do
32
+ return nil if runtime_info.nil?
33
+
34
+ if runtime_info.has_key? 'simulator_device'
35
+ simulator_device = runtime_info['simulator_device']
36
+ if simulator_device && !simulator_device.empty?
37
+ simulator_device
38
+ else
39
+ nil
40
+ end
41
+ else
42
+ physical_device_name = system
43
+ if physical_device_name
44
+ physical_device_name.split(/[\d,.]/).first
45
+ else
46
+ nil
47
+ end
48
+ end
49
+ end.call
50
+ end
51
+
52
+ # @!visibility private
53
+ # The form factor of the device under test.
54
+ #
55
+ # Will be one of:
56
+ #
57
+ # * ipad
58
+ # * iphone 4in
59
+ # * iphone 3.5in
60
+ # * iphone 6
61
+ # * iphone 6+
62
+ # * unknown # if no information can be found.
63
+ #
64
+ # @note iPod is not on this list for a reason! An iPod has an iPhone
65
+ # form factor.
66
+ #
67
+ # @return [String] The form factor of the device under test.
68
+ def form_factor
69
+ @form_factor ||= lambda do
70
+ return nil if runtime_info.nil?
71
+ runtime_info['form_factor']
72
+ end.call
73
+ end
74
+
75
+ # @!visibility private
76
+ # Is the app that is running an iPhone-only app emulated on an iPad?
77
+ #
78
+ # @note If the app is running in emulation mode, there will be a 1x or 2x
79
+ # scale button visible on the iPad.
80
+ #
81
+ # @return [Boolean] true if the app running on this devices is an
82
+ # iPhone-only app emulated on an iPad
83
+ def iphone_app_emulated_on_ipad?
84
+ @iphone_app_emulated_on_ipad ||= lambda do
85
+ return nil if runtime_info.nil?
86
+ runtime_info['iphone_app_emulated_on_ipad']
87
+ end.call
88
+ end
89
+
90
+ # @!visibility private
91
+ # The iOS version on the test device.
92
+ #
93
+ # @return [RunLoop::Version] The major.minor.patch[.pre\d] version of the
94
+ # iOS version on the device.
95
+ def ios_version
96
+ @ios_version ||= lambda do
97
+ return nil if runtime_info.nil?
98
+
99
+ version_string = runtime_info['iOS_version']
100
+
101
+ return nil if version_string.nil? || version_string.empty?
102
+
103
+ begin
104
+ RunLoop::Version.new(version_string)
105
+ rescue => _
106
+ nil
107
+ end
108
+ end.call
109
+ end
110
+
111
+ # @!visibility private
112
+ # Information about the runtime screen dimensions of the app under test.
113
+ #
114
+ # This is a hash of form:
115
+ #
116
+ # ```
117
+ # {
118
+ # :sample => 1,
119
+ # :height => 1334,
120
+ # :width => 750,
121
+ # :scale" => 2
122
+ # }
123
+ # ```
124
+ #
125
+ # @return [Hash] screen dimensions, scale and down/up sampling fraction.
126
+ def screen_dimensions
127
+ @screen_dimensions ||= lambda do
128
+ return nil if runtime_info.nil?
129
+ screen_dimensions = runtime_info['screen_dimensions']
130
+ @screen_dimensions = {}
131
+ screen_dimensions.each_pair do |key,val|
132
+ @screen_dimensions[key.to_sym] = val
133
+ end
134
+ @screen_dimensions
135
+ end.call
136
+ end
137
+
138
+ # @!visibility private
139
+ # The version of the embedded Calabash server that is running in the
140
+ # app under test on this device.
141
+ #
142
+ # @return [RunLoop::Version] The major.minor.patch[.pre\d] version of the
143
+ # embedded Calabash server
144
+ def server_version
145
+ @server_version ||= lambda do
146
+ return nil if runtime_info.nil?
147
+
148
+ version_string = runtime_info['version']
149
+
150
+ return nil if version_string.nil? || version_string.empty?
151
+
152
+ begin
153
+ RunLoop::Version.new(version_string)
154
+ rescue => _
155
+ nil
156
+ end
157
+ end.call
158
+ end
159
+
160
+ private
161
+
162
+ # @!visibility private
163
+ # Details about the device. For iOS Simulators, this will be x86_64,
164
+ # which is not very helpful. For physical devices, this will be the
165
+ # internal Apple device name. For example, the `iPhone 6+` will report
166
+ # `iPhone7,1` and the `iPhone 5s` will report `iPhone6`.
167
+ #
168
+ # @return [String] Information about the device under test.
169
+ def system
170
+ @system ||= lambda do
171
+ return nil if runtime_info.nil?
172
+
173
+ runtime_info['system']
174
+ end.call
175
+ end
176
+
177
+ # @!visibility private
178
+ # The hash passed to initialize.
179
+ attr_reader :runtime_info
180
+
181
+ end
182
+ end
183
+ end
184
+