calabash 1.2.1 → 1.9.9.pre1
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.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +39 -0
- data/LICENSE +204 -21
- data/README.md +36 -6
- data/VERSIONING.md +16 -0
- data/bin/calabash +95 -0
- data/lib/calabash.rb +185 -1
- data/lib/calabash/android.rb +64 -0
- data/lib/calabash/android/adb.rb +277 -0
- data/lib/calabash/android/application.rb +110 -0
- data/lib/calabash/android/build.rb +12 -0
- data/lib/calabash/android/build/application.rb +13 -0
- data/lib/calabash/android/build/build_error.rb +11 -0
- data/lib/calabash/android/build/builder.rb +119 -0
- data/lib/calabash/android/build/java_keystore.rb +177 -0
- data/lib/calabash/android/build/resigner.rb +56 -0
- data/lib/calabash/android/build/test_server.rb +27 -0
- data/lib/calabash/android/console_helpers.rb +44 -0
- data/lib/calabash/android/cucumber.rb +3 -0
- data/lib/calabash/android/device.rb +965 -0
- data/lib/calabash/android/environment.rb +470 -0
- data/lib/calabash/android/gestures.rb +369 -0
- data/lib/calabash/android/interactions.rb +45 -0
- data/lib/calabash/android/lib/.irbrc +55 -0
- data/lib/calabash/android/lib/AndroidManifest.xml +51 -0
- data/lib/calabash/android/lib/TestServer.apk +0 -0
- data/lib/calabash/android/lib/calmd5/arm64-v8a/calmd5 +0 -0
- data/lib/calabash/android/lib/calmd5/arm64-v8a/calmd5-pie +0 -0
- data/lib/calabash/android/lib/calmd5/armeabi-v7a/calmd5 +0 -0
- data/lib/calabash/android/lib/calmd5/armeabi-v7a/calmd5-pie +0 -0
- data/lib/calabash/android/lib/calmd5/armeabi/calmd5 +0 -0
- data/lib/calabash/android/lib/calmd5/armeabi/calmd5-pie +0 -0
- data/lib/calabash/android/lib/calmd5/mips/calmd5 +0 -0
- data/lib/calabash/android/lib/calmd5/mips/calmd5-pie +0 -0
- data/lib/calabash/android/lib/calmd5/mips64/calmd5 +0 -0
- data/lib/calabash/android/lib/calmd5/mips64/calmd5-pie +0 -0
- data/lib/calabash/android/lib/calmd5/x86/calmd5 +0 -0
- data/lib/calabash/android/lib/calmd5/x86/calmd5-pie +0 -0
- data/lib/calabash/android/lib/calmd5/x86_64/calmd5 +0 -0
- data/lib/calabash/android/lib/calmd5/x86_64/calmd5-pie +0 -0
- data/lib/calabash/android/lib/screenshot_taker.jar +0 -0
- data/lib/calabash/android/life_cycle.rb +37 -0
- data/lib/calabash/android/orientation.rb +30 -0
- data/lib/calabash/android/physical_buttons.rb +39 -0
- data/lib/calabash/android/screenshot.rb +9 -0
- data/lib/calabash/android/scroll.rb +5 -0
- data/lib/calabash/android/server.rb +10 -0
- data/lib/calabash/android/text.rb +54 -0
- data/lib/calabash/application.rb +74 -0
- data/lib/calabash/cli.rb +12 -0
- data/lib/calabash/cli/build.rb +33 -0
- data/lib/calabash/cli/console.rb +90 -0
- data/lib/calabash/cli/generate.rb +110 -0
- data/lib/calabash/cli/helpers.rb +130 -0
- data/lib/calabash/cli/resign.rb +33 -0
- data/lib/calabash/cli/run.rb +99 -0
- data/lib/calabash/cli/setup_keystore.rb +39 -0
- data/lib/calabash/color.rb +32 -0
- data/lib/calabash/console_helpers.rb +90 -0
- data/lib/calabash/defaults.rb +56 -0
- data/lib/calabash/device.rb +401 -0
- data/lib/calabash/environment.rb +75 -0
- data/lib/calabash/gestures.rb +384 -0
- data/lib/calabash/http.rb +8 -0
- data/lib/calabash/http/error.rb +15 -0
- data/lib/calabash/http/request.rb +42 -0
- data/lib/calabash/http/retriable_client.rb +156 -0
- data/lib/calabash/interactions.rb +105 -0
- data/lib/calabash/ios.rb +37 -0
- data/lib/calabash/ios/application.rb +119 -0
- data/lib/calabash/ios/conditions.rb +79 -0
- data/lib/calabash/ios/console_helpers.rb +72 -0
- data/lib/calabash/ios/device.rb +24 -0
- data/lib/calabash/ios/device/device_implementation.rb +779 -0
- data/lib/calabash/ios/device/gestures_mixin.rb +167 -0
- data/lib/calabash/ios/device/keyboard_mixin.rb +133 -0
- data/lib/calabash/ios/device/physical_device_mixin.rb +266 -0
- data/lib/calabash/ios/device/rotation_mixin.rb +124 -0
- data/lib/calabash/ios/device/routes/backdoor_route_mixin.rb +86 -0
- data/lib/calabash/ios/device/routes/condition_route_mixin.rb +62 -0
- data/lib/calabash/ios/device/routes/error.rb +8 -0
- data/lib/calabash/ios/device/routes/handle_route_mixin.rb +102 -0
- data/lib/calabash/ios/device/routes/map_route_mixin.rb +38 -0
- data/lib/calabash/ios/device/routes/playback_route_mixin.rb +70 -0
- data/lib/calabash/ios/device/routes/response_parser.rb +48 -0
- data/lib/calabash/ios/device/routes/uia_route_mixin.rb +238 -0
- data/lib/calabash/ios/device/runtime_attributes.rb +184 -0
- data/lib/calabash/ios/device/status_bar_mixin.rb +17 -0
- data/lib/calabash/ios/device/text_mixin.rb +19 -0
- data/lib/calabash/ios/device/uia_keyboard_mixin.rb +188 -0
- data/lib/calabash/ios/device/uia_mixin.rb +12 -0
- data/lib/calabash/ios/environment.rb +41 -0
- data/lib/calabash/ios/interactions.rb +10 -0
- data/lib/calabash/ios/lib/.irbrc +55 -0
- data/lib/calabash/ios/lib/recordings/rotate_left_home_down_ipad.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_left_home_down_iphone.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_left_home_left_ipad.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_left_home_left_iphone.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_left_home_right_ipad.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_left_home_right_iphone.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_left_home_up_ipad.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_left_home_up_iphone.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_right_home_down_ipad.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_right_home_down_iphone.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_right_home_left_ipad.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_right_home_left_iphone.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_right_home_right_ipad.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_right_home_right_iphone.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_right_home_up_ipad.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_right_home_up_iphone.base64 +2 -0
- data/lib/calabash/ios/orientation.rb +117 -0
- data/lib/calabash/ios/scroll.rb +504 -0
- data/lib/calabash/ios/server.rb +73 -0
- data/lib/calabash/ios/text.rb +248 -0
- data/lib/calabash/ios/uia.rb +24 -0
- data/lib/calabash/lib/skeleton/config/cucumber.yml +6 -0
- data/lib/calabash/lib/skeleton/features/sample.feature +5 -0
- data/lib/calabash/lib/skeleton/features/step_definitions/calabash_steps.rb +29 -0
- data/lib/calabash/lib/skeleton/features/support/env.rb +54 -0
- data/lib/calabash/lib/skeleton/features/support/hooks.rb +83 -0
- data/lib/calabash/life_cycle.rb +111 -0
- data/lib/calabash/location.rb +51 -0
- data/lib/calabash/logger.rb +87 -0
- data/lib/calabash/orientation.rb +84 -0
- data/lib/calabash/page.rb +35 -0
- data/lib/calabash/patch.rb +14 -0
- data/lib/calabash/patch/array.rb +16 -0
- data/lib/calabash/patch/run_loop.rb +90 -0
- data/lib/calabash/query.rb +160 -0
- data/lib/calabash/query_result.rb +85 -0
- data/lib/calabash/screenshot.rb +89 -0
- data/lib/calabash/server.rb +16 -0
- data/lib/calabash/text.rb +76 -0
- data/lib/calabash/utility.rb +58 -0
- data/lib/calabash/version.rb +3 -1
- data/lib/calabash/wait.rb +474 -0
- metadata +462 -24
@@ -0,0 +1,167 @@
|
|
1
|
+
module Calabash
|
2
|
+
module IOS
|
3
|
+
# @!visibility private
|
4
|
+
#
|
5
|
+
# Gestures should wait for the views involved before performing the
|
6
|
+
# gesture.
|
7
|
+
#
|
8
|
+
# 1. Wait for the view or views.
|
9
|
+
# 2. Find the absolute coordinates of the gesture.
|
10
|
+
# 3. Pass the coordinates to the Calabash UIA offset API.
|
11
|
+
# 4. Return the views involved in the gesture as QueryResults.
|
12
|
+
#
|
13
|
+
# @todo Needs unit tests.
|
14
|
+
module GesturesMixin
|
15
|
+
|
16
|
+
def _tap(query, options={})
|
17
|
+
view_to_touch = _gesture_waiter.wait_for_view(query, options)
|
18
|
+
|
19
|
+
offset = uia_center_of_view(view_to_touch)
|
20
|
+
|
21
|
+
uia_serialize_and_call(:tapOffset, offset, options)
|
22
|
+
|
23
|
+
Calabash::QueryResult.create([view_to_touch], query)
|
24
|
+
end
|
25
|
+
|
26
|
+
def _double_tap(query, options={})
|
27
|
+
view_to_touch = _gesture_waiter.wait_for_view(query, options)
|
28
|
+
|
29
|
+
offset = uia_center_of_view(view_to_touch)
|
30
|
+
|
31
|
+
uia_serialize_and_call(:doubleTapOffset, offset, options)
|
32
|
+
|
33
|
+
Calabash::QueryResult.create([view_to_touch], query)
|
34
|
+
end
|
35
|
+
|
36
|
+
def _long_press(query, options={})
|
37
|
+
|
38
|
+
begin
|
39
|
+
_expect_valid_duration(options)
|
40
|
+
rescue ArgumentError => e
|
41
|
+
raise ArgumentError e
|
42
|
+
end
|
43
|
+
|
44
|
+
view_to_touch = _gesture_waiter.wait_for_view(query, options)
|
45
|
+
|
46
|
+
offset = uia_center_of_view(view_to_touch)
|
47
|
+
|
48
|
+
uia_serialize_and_call(:touchHoldOffset, options[:duration], offset)
|
49
|
+
|
50
|
+
Calabash::QueryResult.create([view_to_touch], query)
|
51
|
+
end
|
52
|
+
|
53
|
+
def _pan_between(query_from, query_to, options={})
|
54
|
+
|
55
|
+
begin
|
56
|
+
_expect_valid_duration(options)
|
57
|
+
rescue ArgumentError => e
|
58
|
+
raise ArgumentError e
|
59
|
+
end
|
60
|
+
|
61
|
+
from_view = _gesture_waiter.wait_for_view(query_from, options)
|
62
|
+
to_view = _gesture_waiter.wait_for_view(query_to, options)
|
63
|
+
|
64
|
+
from_offset = uia_center_of_view(from_view)
|
65
|
+
to_offset = uia_center_of_view(to_view)
|
66
|
+
|
67
|
+
uia_serialize_and_call(:panOffset, from_offset, to_offset, options)
|
68
|
+
|
69
|
+
{
|
70
|
+
:from => Calabash::QueryResult.create([from_view], query_from),
|
71
|
+
:to => Calabash::QueryResult.create([to_view], query_to)
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
# The default to and from for the pan_* methods are not good for iOS.
|
76
|
+
#
|
77
|
+
# * from: {x: 90, y: 50}
|
78
|
+
# * to: {x: 10, y: 50}
|
79
|
+
#
|
80
|
+
# If the view has a UINavigationBar or UITabBar, the defaults will
|
81
|
+
# cause vertical gestures to start and/or end on one of these bars.
|
82
|
+
#
|
83
|
+
# dragInsideWithOptions broke in iOS 7, so the condition should really be
|
84
|
+
# `Device.default.simulator? && !Device.ios6?`, but I haven't checked on
|
85
|
+
# iOS 9 yet, so I will leave the condition out.
|
86
|
+
def _pan(query, from, to, options={})
|
87
|
+
if Device.default.simulator?
|
88
|
+
message = [
|
89
|
+
"Apple's UIAutomation `dragInsideWithOptions` API is broken for iOS > 7",
|
90
|
+
'If you are trying to scroll on a UITableView or UICollectionView, try using the scroll_* methods'
|
91
|
+
].join("\n")
|
92
|
+
|
93
|
+
raise message
|
94
|
+
end
|
95
|
+
|
96
|
+
begin
|
97
|
+
_expect_valid_duration(options)
|
98
|
+
rescue ArgumentError => e
|
99
|
+
raise ArgumentError e
|
100
|
+
end
|
101
|
+
|
102
|
+
view_to_pan = _gesture_waiter.wait_for_view(query, options)
|
103
|
+
|
104
|
+
rect = view_to_pan['rect']
|
105
|
+
|
106
|
+
from_x = rect['width'] * (from[:x]/100.0)
|
107
|
+
from_y = rect['height'] * (from[:y]/100.0)
|
108
|
+
from_offset = percent(from_x, from_y)
|
109
|
+
|
110
|
+
to_x = rect['width'] * (to[:x]/100.0)
|
111
|
+
to_y = rect['height'] * (to[:y]/100.0)
|
112
|
+
to_offset = percent(to_x, to_y)
|
113
|
+
|
114
|
+
uia_serialize_and_call(:panOffset, from_offset, to_offset)
|
115
|
+
|
116
|
+
Calabash::QueryResult.create([view_to_pan], query)
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
# !@visibility private
|
122
|
+
#
|
123
|
+
# Unlike the Calabash Android server, the iOS server does not wait
|
124
|
+
# before gestures, so the client must do the waiting. The _gesture_waiter
|
125
|
+
# allows access to query, wait, etc. without having to include all of
|
126
|
+
# Calabash in this module.
|
127
|
+
#
|
128
|
+
# @todo Replace with waiting on the iOS Server
|
129
|
+
def _gesture_waiter
|
130
|
+
lambda do |reference_to_self|
|
131
|
+
Class.new do
|
132
|
+
# world_for_device will return a copy of the module Calabash::IOS,
|
133
|
+
# which has redefined Calabash.default_device to reference this
|
134
|
+
# device. We should not keep a reference to gesture_waiter
|
135
|
+
# because of this, as the user might change a constant or class
|
136
|
+
# variable in Calabash.
|
137
|
+
include reference_to_self.send(:world_for_device)
|
138
|
+
|
139
|
+
define_method(:query) do |query, *args|
|
140
|
+
reference_to_self.map_route(query, :query, *args)
|
141
|
+
end
|
142
|
+
|
143
|
+
def to_s
|
144
|
+
'#<Calabash::IOS::GestureWaiter>'
|
145
|
+
end
|
146
|
+
|
147
|
+
def inspect
|
148
|
+
to_s
|
149
|
+
end
|
150
|
+
end.new
|
151
|
+
end.call(self)
|
152
|
+
end
|
153
|
+
|
154
|
+
def _expect_valid_duration(options)
|
155
|
+
duration = options[:duration].to_f
|
156
|
+
if duration < 0.5 || duration > 60
|
157
|
+
message = [
|
158
|
+
"Expected :duration 0.5 <= '#{duration}' <= 60",
|
159
|
+
'On iOS, gesture durations must be between 0.5 and 60 seconds.',
|
160
|
+
'This is a limitation enforced by the UIAutomation API.'
|
161
|
+
].join("\n")
|
162
|
+
raise ArgumentError, message
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
module Calabash
|
2
|
+
module IOS
|
3
|
+
|
4
|
+
# @!visibility private
|
5
|
+
module KeyboardMixin
|
6
|
+
|
7
|
+
# Returns true if a docked keyboard is visible.
|
8
|
+
#
|
9
|
+
# A docked keyboard is pinned to the bottom of the view.
|
10
|
+
#
|
11
|
+
# Keyboards on the iPhone and iPod are docked.
|
12
|
+
def docked_keyboard_visible?
|
13
|
+
query_result = query_for_keyboard
|
14
|
+
return false if query_result.empty?
|
15
|
+
|
16
|
+
return true if device_family_iphone?
|
17
|
+
|
18
|
+
# iPad
|
19
|
+
rect = query_result.first['rect']
|
20
|
+
orientation = status_bar_orientation.to_sym
|
21
|
+
case orientation
|
22
|
+
when :left then
|
23
|
+
rect['center_x'] == 592 && rect['center_y'] == 512
|
24
|
+
when :right then
|
25
|
+
rect['center_x'] == 176 && rect['center_y'] == 512
|
26
|
+
when :up then
|
27
|
+
rect['center_x'] == 384 && rect['center_y'] == 132
|
28
|
+
when :down then
|
29
|
+
rect['center_x'] == 384 && rect['center_y'] == 892
|
30
|
+
else
|
31
|
+
false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns true if an undocked keyboard is visible.
|
36
|
+
#
|
37
|
+
# A undocked keyboard is floats in the middle of the view.
|
38
|
+
#
|
39
|
+
# Only iPad keyboards can be undocked.
|
40
|
+
def undocked_keyboard_visible?
|
41
|
+
return false if device_family_iphone?
|
42
|
+
|
43
|
+
return false if query_for_keyboard.empty?
|
44
|
+
|
45
|
+
not docked_keyboard_visible?
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns true if a split keyboard is visible.
|
49
|
+
#
|
50
|
+
# A split keyboard is floats in the middle of the view and is split to
|
51
|
+
# allow faster thumb typing
|
52
|
+
#
|
53
|
+
# Only iPad keyboards can be split.
|
54
|
+
def split_keyboard_visible?
|
55
|
+
return false if device_family_iphone?
|
56
|
+
query_for_keyboard_keys.count > 0 && query_for_keyboard.empty?
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns true if there is a visible keyboard.
|
60
|
+
def keyboard_visible?
|
61
|
+
docked_keyboard_visible? || undocked_keyboard_visible? || split_keyboard_visible?
|
62
|
+
end
|
63
|
+
|
64
|
+
# Returns the the text in the first responder.
|
65
|
+
#
|
66
|
+
# The first responder will be the UITextField or UITextView instance
|
67
|
+
# that is associated with the visible keyboard.
|
68
|
+
#
|
69
|
+
# Returns empty string if no textField or textView elements are found to be
|
70
|
+
# the first responder. Otherwise, it will return the text in the
|
71
|
+
# UITextField or UITextField that is associated with the keyboard.
|
72
|
+
def text_from_keyboard_first_responder
|
73
|
+
raise 'There must be a visible keyboard.' unless keyboard_visible?
|
74
|
+
|
75
|
+
text = ''
|
76
|
+
['textField', 'textView'].each do |ui_class|
|
77
|
+
text = query_for_text_of_first_responder(ui_class)
|
78
|
+
if text.nil?
|
79
|
+
text = ''
|
80
|
+
else
|
81
|
+
break
|
82
|
+
end
|
83
|
+
end
|
84
|
+
text
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
# @!visibility private
|
90
|
+
# Returns a query string for detecting a keyboard.
|
91
|
+
KEYBOARD_QUERY = "view:'UIKBKeyplaneView'"
|
92
|
+
KEYBOARD_KEY_QUERY = "view:'UIKBKeyView'"
|
93
|
+
|
94
|
+
def device_family_iphone?
|
95
|
+
family = device_family
|
96
|
+
family == 'iPhone'
|
97
|
+
end
|
98
|
+
|
99
|
+
# Unlike the Calabash Android server, the iOS server does not wait
|
100
|
+
# before gestures. We need to do this in the client for now.
|
101
|
+
# @todo Replace with waiting on the iOS Server
|
102
|
+
def keyboard_waiter
|
103
|
+
@keyboard_waiter ||= lambda do |reference_to_self|
|
104
|
+
Class.new do
|
105
|
+
include Calabash::Wait
|
106
|
+
define_method(:query) do |query, *args|
|
107
|
+
reference_to_self.map_route(query, :query, *args)
|
108
|
+
end
|
109
|
+
end.new
|
110
|
+
end.call(self)
|
111
|
+
end
|
112
|
+
|
113
|
+
def query_for_keyboard
|
114
|
+
keyboard_waiter.query(KEYBOARD_QUERY)
|
115
|
+
end
|
116
|
+
|
117
|
+
# When the split keyboard is showing, KEYBOARD_QUERY will return no
|
118
|
+
# results. UIKBKeyView are the individual key views on the keyboard.
|
119
|
+
def query_for_keyboard_keys
|
120
|
+
keyboard_waiter.query(KEYBOARD_KEY_QUERY)
|
121
|
+
end
|
122
|
+
|
123
|
+
def query_for_text_of_first_responder(query)
|
124
|
+
result = keyboard_waiter.query("#{query} isFirstResponder:1", :text)
|
125
|
+
if result.empty?
|
126
|
+
nil
|
127
|
+
else
|
128
|
+
result.first
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,266 @@
|
|
1
|
+
module Calabash
|
2
|
+
module IOS
|
3
|
+
|
4
|
+
# @!visibility private
|
5
|
+
# A mixin for IOS::Device that provides methods that users can override
|
6
|
+
# to use a third-party tool like `ideviceinstaller` or `ios-deploy` to
|
7
|
+
# manage apps on physical devices.
|
8
|
+
#
|
9
|
+
#
|
10
|
+
# Calabash cannot manage apps on physical devices. There are third-party
|
11
|
+
# tools you can use to manage apps on devices. Two popular tools are
|
12
|
+
# ideviceinstaller and ios-deploy. Both can be installed using homebrew.
|
13
|
+
#
|
14
|
+
# To integrate these tools, Calabash provides several methods for you to
|
15
|
+
# override in your project. In your `features/support/` directory, you
|
16
|
+
# can patch Calabash::IOS::Device with your own implementation of these
|
17
|
+
# methods. The five methods to override are:
|
18
|
+
#
|
19
|
+
# 1. app_installed_on_physical_device?
|
20
|
+
# 2. install_app_on_physical_device
|
21
|
+
# 3. ensure_app_installed_on_physical_device
|
22
|
+
# 4. clear_app_data_on_physical_device
|
23
|
+
# 5. uninstall_app_on_physical_device
|
24
|
+
#
|
25
|
+
#
|
26
|
+
# ```
|
27
|
+
# # features/support/ideviceinstaller.rb
|
28
|
+
#
|
29
|
+
# require 'fileutils'
|
30
|
+
# class Calabash::IOS::Device
|
31
|
+
#
|
32
|
+
# def app_installed_on_physical_device?(application, device_udid)
|
33
|
+
# out = `/usr/local/bin/ideviceinstaller --udid #{device_udid} --list-apps`
|
34
|
+
# out.split(/\s/).include? application.identifier
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# def install_app_on_physical_device(application, device_udid)
|
38
|
+
#
|
39
|
+
# if app_installed_on_physical_device?(application, device_udid)
|
40
|
+
# uninstall_app_on_physical_device(application, device_udid)
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# args =
|
44
|
+
# [
|
45
|
+
# '--udid', device_udid,
|
46
|
+
# '--install', application.path
|
47
|
+
# ]
|
48
|
+
#
|
49
|
+
# log = FileUtils.touch('./ideviceinstaller.log')
|
50
|
+
# system('/usr/local/bin/ideviceinstaller', *args, {:out => log})
|
51
|
+
#
|
52
|
+
# exit_code = $?
|
53
|
+
# unless exit_code == 0
|
54
|
+
# raise "Could not install the app (#{exit_code}). See #{File.expand_path(log)}"
|
55
|
+
# end
|
56
|
+
# true
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# def uninstall_app_on_physical_device(application, device_udid)
|
60
|
+
#
|
61
|
+
# if app_installed_on_physical_device?(application, device_udid)
|
62
|
+
#
|
63
|
+
# args =
|
64
|
+
# [
|
65
|
+
# '--udid', device_udid,
|
66
|
+
# '--uninstall', application.identifier
|
67
|
+
# ]
|
68
|
+
#
|
69
|
+
# log = FileUtils.touch('./ideviceinstaller.log')
|
70
|
+
# system('/usr/local/bin/ideviceinstaller', *args, {:out => log})
|
71
|
+
#
|
72
|
+
# exit_code = $?
|
73
|
+
# unless exit_code == 0
|
74
|
+
# raise "Could not uninstall the app (#{exit_code}). See #{File.expand_path(log)}"
|
75
|
+
# end
|
76
|
+
# end
|
77
|
+
# true
|
78
|
+
# end
|
79
|
+
#
|
80
|
+
# def ensure_app_installed_on_physical_device(application, device_udid)
|
81
|
+
# unless app_installed_on_physical_device?(application, device_udid)
|
82
|
+
# install_app_on_physical_device(application, device_udid)
|
83
|
+
# end
|
84
|
+
# true
|
85
|
+
# end
|
86
|
+
#
|
87
|
+
# # The only way to clear the data is to uninstall the app.
|
88
|
+
# def clear_app_data_on_physical_device(application, device_udid)
|
89
|
+
# if app_installed_on_physical_device?(application, device_udid)
|
90
|
+
# install_app_on_physical_device(application, device_udid)
|
91
|
+
# end
|
92
|
+
# true
|
93
|
+
# end
|
94
|
+
# end
|
95
|
+
# ```
|
96
|
+
#
|
97
|
+
# For a real-world example of a ruby wrapper around the ideviceinstaller
|
98
|
+
# command-line tool, see https://github.com/calabash/ios-smoke-test-app.
|
99
|
+
#
|
100
|
+
# @see #app_installed_on_physical_device?
|
101
|
+
# @see #install_app_on_physical_device
|
102
|
+
# @see #ensure_app_installed_on_physical_device
|
103
|
+
# @see #clear_app_data_on_physical_device
|
104
|
+
# @see #uninstall_app_on_physical_device
|
105
|
+
#
|
106
|
+
# @see http://brew.sh/
|
107
|
+
# @see https://github.com/libimobiledevice/ideviceinstaller
|
108
|
+
# @see https://github.com/phonegap/ios-deploy
|
109
|
+
# @see https://github.com/calabash/ios-smoke-test-app/blob/master/CalSmokeApp/features/support/ideviceinstaller.rb
|
110
|
+
# @see https://github.com/blueboxsecurity/idevice
|
111
|
+
#
|
112
|
+
# For an real-world example of a ruby wrapper around the ideviceinstaller
|
113
|
+
# tool, see /blob/master/CalSmokeApp/features/support/ideviceinstaller.rb
|
114
|
+
module PhysicalDeviceMixin
|
115
|
+
|
116
|
+
# Install an app on physical device. To fit into Calabash's app lifecycle
|
117
|
+
# model, implementations of this method must follow these rules:
|
118
|
+
#
|
119
|
+
# 1. If the app is installed, uninstall it, and then install it.
|
120
|
+
# 2. If the app cannot be uninstalled or installed, raise a StandardError.
|
121
|
+
#
|
122
|
+
# param [Calabash::IOS::Application] application The application to
|
123
|
+
# to install. The important methods on application are `path` and
|
124
|
+
# `identifier`.
|
125
|
+
# @param [String] device_udid The identifier of the device to install the
|
126
|
+
# application on.
|
127
|
+
#
|
128
|
+
# @return [Boolean] If the app was installed ont the device.
|
129
|
+
#
|
130
|
+
# @raise [Calabash::AbstractMethodError] If this method is not implemented
|
131
|
+
# by the user.
|
132
|
+
def install_app_on_physical_device(application, device_udid)
|
133
|
+
logger.log('To install an ipa on a physical device, you must extend', :info)
|
134
|
+
logger.log('Calabash::IOS::Device and implement the #install_app_on_physical_device', :info)
|
135
|
+
logger.log('method that using a third-party tool to interact with physical devices.', :info)
|
136
|
+
logger.log('For an example of an implementation using ideviceinstaller, see:', :info)
|
137
|
+
logger.log('https://github.com/calabash/ios-smoke-test-app.', :info)
|
138
|
+
raise Calabash::AbstractMethodError,
|
139
|
+
'Device install_app_on_physical_device must be implemented by you.'
|
140
|
+
end
|
141
|
+
|
142
|
+
# Ensures that `application` is installed on a physical device. To fit
|
143
|
+
# into Calabash's app lifecycle model, implementations of this method must
|
144
|
+
# follow these rules:
|
145
|
+
#
|
146
|
+
# 1. If the app is not installed, install it.
|
147
|
+
# 2. If the app is installed, return true
|
148
|
+
# 3. If the app cannot be installed, raise a StandardError.
|
149
|
+
#
|
150
|
+
# @param [Calabash::IOS::Application] application The application to
|
151
|
+
# to install. The important methods on application are `path` and
|
152
|
+
# `identifier`.
|
153
|
+
# @param [String] device_udid The identifier of the device to install the
|
154
|
+
# application on.
|
155
|
+
#
|
156
|
+
# @return [Boolean] If the app is installed on the physical_device.
|
157
|
+
#
|
158
|
+
# @raise [Calabash::AbstractMethodError] If this method is not implemented
|
159
|
+
# by the user.
|
160
|
+
def ensure_app_installed_on_physical_device(application, device_udid)
|
161
|
+
logger.log('To check if an app installed on a physical device, you must extend', :info)
|
162
|
+
logger.log('Calabash::IOS::Device and implement the #ensure_app_installed_on_device', :info)
|
163
|
+
logger.log('method that using a third-party tool to interact with physical devices.', :info)
|
164
|
+
logger.log('For an example of an implementation using ideviceinstaller, see:', :info)
|
165
|
+
logger.log('https://github.com/calabash/ios-smoke-test-app.', :info)
|
166
|
+
raise Calabash::AbstractMethodError,
|
167
|
+
'Device ensure_app_installed_on_device must be implemented by you.'
|
168
|
+
end
|
169
|
+
|
170
|
+
# Clears the application's data from a physical device. To fit into
|
171
|
+
# Calabash's app lifecycle model, implementations of this method must
|
172
|
+
# follow these rules:
|
173
|
+
#
|
174
|
+
# 1. The data in the applications sandbox must be reset to a good known
|
175
|
+
# state. What that means for your application is up to you to
|
176
|
+
# decide. Generally, this means you should remove _all_ files from
|
177
|
+
# the application's sandbox.
|
178
|
+
# 2. If the data has been reset, return true.
|
179
|
+
# 3. If the app data cannot be cleared, raise a StandardError.
|
180
|
+
#
|
181
|
+
# Some kinds of user data are very difficult to clear. For example,
|
182
|
+
# values stored in NSUserDefaults are not removed when an app is
|
183
|
+
# uninstalled. The same is true for values stored in the Keychain.
|
184
|
+
#
|
185
|
+
# You might need to add logic in your Cucumber Before hooks to clear
|
186
|
+
# such data.
|
187
|
+
#
|
188
|
+
# @param [Calabash::IOS::Application] application The application to
|
189
|
+
# to install. The important methods on application are `path` and
|
190
|
+
# `identifier`.
|
191
|
+
# @param [String] device_udid The identifier of the device to install the
|
192
|
+
# application on.
|
193
|
+
#
|
194
|
+
# @return [Boolean] Return true if the application data was cleared.
|
195
|
+
#
|
196
|
+
# @raise [Calabash::AbstractMethodError] If this method is not implemented
|
197
|
+
# by the user.
|
198
|
+
def clear_app_data_on_physical_device(application, device_udid)
|
199
|
+
logger.log('To clear app data on a physical device, you must extend', :info)
|
200
|
+
logger.log('Calabash::IOS::Device and implement the #clear_app_data_on_physical_device', :info)
|
201
|
+
logger.log('method using a third-party tool to interact with physical devices.', :info)
|
202
|
+
logger.log('For an example of an implementation using ideviceinstaller, see:', :info)
|
203
|
+
logger.log('https://github.com/calabash/ios-smoke-test-app.', :info)
|
204
|
+
raise Calabash::AbstractMethodError,
|
205
|
+
'Device clear_app_data_on_physical_device must be implemented by you.'
|
206
|
+
end
|
207
|
+
|
208
|
+
# Returns true if the application is installed on a physical device. To
|
209
|
+
# fit into Calabash's app lifecycle model, implementations of this method
|
210
|
+
# must follow these rules:
|
211
|
+
#
|
212
|
+
# 1. If the app is installed, this method must return true.
|
213
|
+
# 2. If the app is not installed, this method must return false.
|
214
|
+
# 3. If the state of the app on the device cannot be determined, raise
|
215
|
+
# a RuntimeError.
|
216
|
+
#
|
217
|
+
# @param [Calabash::IOS::Application] application The application to
|
218
|
+
# to install. The important methods on application are `path` and
|
219
|
+
# `identifier`.
|
220
|
+
# @param [String] device_udid The identifier of the device to install the
|
221
|
+
# application on.
|
222
|
+
#
|
223
|
+
# @return [Boolean] Return true if the application is installed on the
|
224
|
+
# device.
|
225
|
+
#
|
226
|
+
# @raise [Calabash::AbstractMethodError] If this method is not implemented
|
227
|
+
# by the user.
|
228
|
+
def app_installed_on_physical_device?(application, device_udid)
|
229
|
+
logger.log('To determine if an app is installed on a physical device, you must extend', :info)
|
230
|
+
logger.log('Calabash::IOS::Device and implement the #app_installed_on_physical_device', :info)
|
231
|
+
logger.log('method using a third-party tool to interact with physical devices.', :info)
|
232
|
+
logger.log('For an example of an implementation using ideviceinstaller, see:', :info)
|
233
|
+
logger.log('https://github.com/calabash/ios-smoke-test-app.', :info)
|
234
|
+
raise Calabash::AbstractMethodError,
|
235
|
+
'Device app_installed_on_physical_device? must be implemented by you.'
|
236
|
+
end
|
237
|
+
|
238
|
+
# Uninstalls an application from a physical device. To fit into Calabash's
|
239
|
+
# app lifecycle model, implementations of this method must follow these
|
240
|
+
# rules:
|
241
|
+
#
|
242
|
+
# 1. Return true if the app was uninstalled.
|
243
|
+
# 2. Raise an error if the app cannot be uninstalled.
|
244
|
+
#
|
245
|
+
# @param [Calabash::IOS::Application] application The application to
|
246
|
+
# to install. The important methods on application are `path` and
|
247
|
+
# `identifier`.
|
248
|
+
# @param [String] device_udid The identifier of the device to install the
|
249
|
+
# application on.
|
250
|
+
#
|
251
|
+
# @return [Boolean] Return true if the application was uninstalled.
|
252
|
+
#
|
253
|
+
# @raise [Calabash::AbstractMethodError] If this method is not implemented
|
254
|
+
# by the user.
|
255
|
+
def uninstall_app_on_physical_device(application, device_udid)
|
256
|
+
logger.log('To uninstall an ipa on a physical device, you must extend', :info)
|
257
|
+
logger.log('Calabash::IOS::Device and implement the #uninstall_app_on_physical_device', :info)
|
258
|
+
logger.log('method that using a third-party tool to interact with physical devices.', :info)
|
259
|
+
logger.log('For an example of an implementation using ideviceinstaller, see:', :info)
|
260
|
+
logger.log('https://github.com/calabash/ios-smoke-test-app.', :info)
|
261
|
+
raise Calabash::AbstractMethodError,
|
262
|
+
'Device uninstall_app_on_physical_device must be implemented by you.'
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|