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.
- 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
|