calabash-cucumber 0.9.169.pre2 → 0.9.169.pre5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +14 -1
- data/bin/calabash-ios-setup.rb +2 -4
- data/bin/calabash-ios-sim.rb +10 -40
- data/calabash-cucumber.gemspec +25 -22
- data/features-skeleton/support/01_launch.rb +1 -1
- data/lib/calabash-cucumber.rb +13 -1
- data/lib/calabash-cucumber/actions/instruments_actions.rb +0 -4
- data/lib/calabash-cucumber/actions/playback_actions.rb +0 -4
- data/lib/calabash-cucumber/core.rb +9 -16
- data/lib/calabash-cucumber/device.rb +11 -2
- data/lib/calabash-cucumber/environment_helpers.rb +4 -56
- data/lib/calabash-cucumber/ios7_operations.rb +4 -2
- data/lib/calabash-cucumber/keyboard_helpers.rb +6 -3
- data/lib/calabash-cucumber/launch/simulator_helper.rb +40 -386
- data/lib/calabash-cucumber/launch/simulator_launcher.rb +534 -0
- data/lib/calabash-cucumber/launcher.rb +172 -36
- data/lib/calabash-cucumber/operations.rb +3 -4
- data/lib/calabash-cucumber/playback_helpers.rb +15 -29
- data/lib/calabash-cucumber/rotation_helpers.rb +14 -10
- data/lib/calabash-cucumber/status_bar_helpers.rb +5 -1
- data/lib/calabash-cucumber/uia.rb +6 -12
- data/lib/calabash-cucumber/utils/logging.rb +97 -0
- data/lib/calabash-cucumber/utils/plist_buddy.rb +178 -0
- data/lib/calabash-cucumber/utils/simulator_accessibility.rb +250 -0
- data/lib/calabash-cucumber/utils/xctools.rb +95 -0
- data/lib/calabash-cucumber/version.rb +197 -2
- data/lib/calabash-cucumber/wait_helpers.rb +16 -20
- data/scripts/.irbrc +11 -6
- data/scripts/com.example.plist +0 -0
- data/scripts/launch.rb +1 -1
- data/spec/bin/calabash_ios_sim_spec.rb +24 -0
- data/spec/launcher_spec.rb +76 -0
- data/spec/logging_spec.rb +38 -0
- data/spec/plist_buddy_spec.rb +99 -0
- data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/Default-568h@2x.png +0 -0
- data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/Info.plist +0 -0
- data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/LPSimpleExample-cal +0 -0
- data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/PkgInfo +1 -0
- data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/en.lproj/InfoPlist.strings +0 -0
- data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/en.lproj/LPFirstViewController.nib +0 -0
- data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/en.lproj/LPFirstViewController~ipad.nib +0 -0
- data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/en.lproj/LPFourthViewController.nib +0 -0
- data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/en.lproj/LPFourthViewController~ipad.nib +0 -0
- data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/en.lproj/LPSecondViewController.nib +0 -0
- data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/en.lproj/LPSecondViewController~ipad.nib +0 -0
- data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/en.lproj/LPThirdViewController.nib +0 -0
- data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/en.lproj/LPThirdViewController~ipad.nib +0 -0
- data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/first.png +0 -0
- data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/first@2x.png +0 -0
- data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/second.png +0 -0
- data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/second@2x.png +0 -0
- data/spec/resources/plist_buddy/com.example.plist +0 -0
- data/spec/resources/plist_buddy/com.testing.plist +18 -0
- data/spec/simulator_accessibility_spec.rb +144 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/xctools_spec.rb +58 -0
- metadata +120 -34
@@ -1,7 +1,11 @@
|
|
1
|
+
require 'calabash-cucumber/utils/logging'
|
2
|
+
|
1
3
|
module Calabash
|
2
4
|
module Cucumber
|
3
5
|
module RotationHelpers #=> Connection, StatusBarHelpers
|
4
6
|
|
7
|
+
include Calabash::Cucumber::Logging
|
8
|
+
|
5
9
|
def rotation_candidates
|
6
10
|
%w(rotate_left_home_down rotate_left_home_left rotate_left_home_right rotate_left_home_up
|
7
11
|
rotate_right_home_down rotate_right_home_left rotate_right_home_right rotate_right_home_up)
|
@@ -18,15 +22,15 @@ module Calabash
|
|
18
22
|
def rotate_home_button_to(dir)
|
19
23
|
dir_sym = dir.to_sym
|
20
24
|
if dir_sym.eql?(:top)
|
21
|
-
if
|
22
|
-
|
25
|
+
if full_console_logging?
|
26
|
+
calabash_warn "converting '#{dir}' to ':up' - please adjust your code"
|
23
27
|
end
|
24
28
|
dir_sym = :up
|
25
29
|
end
|
26
30
|
|
27
31
|
if dir_sym.eql?(:bottom)
|
28
|
-
if
|
29
|
-
|
32
|
+
if full_console_logging?
|
33
|
+
calabash_warn "converting '#{dir}' to ':down' - please adjust your code"
|
30
34
|
end
|
31
35
|
dir_sym = :down
|
32
36
|
end
|
@@ -46,7 +50,7 @@ module Calabash
|
|
46
50
|
return res if res.eql? dir_sym
|
47
51
|
|
48
52
|
rotation_candidates.each { |candidate|
|
49
|
-
if
|
53
|
+
if full_console_logging?
|
50
54
|
puts "try to rotate to '#{dir_sym}' using '#{candidate}'"
|
51
55
|
end
|
52
56
|
playback(candidate)
|
@@ -63,10 +67,10 @@ module Calabash
|
|
63
67
|
return if res.eql? dir_sym
|
64
68
|
}
|
65
69
|
|
66
|
-
if
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
+
if full_console_logging?
|
71
|
+
calabash_warn "Could not rotate home button to '#{dir}'."
|
72
|
+
calabash_warn 'Is rotation enabled for this controller?'
|
73
|
+
calabash_warn "Will return 'down'"
|
70
74
|
end
|
71
75
|
:down
|
72
76
|
end
|
@@ -99,7 +103,7 @@ module Calabash
|
|
99
103
|
end
|
100
104
|
|
101
105
|
if rotate_cmd.nil?
|
102
|
-
if
|
106
|
+
if full_console_logging?
|
103
107
|
puts "Could not rotate device in direction '#{dir}' with orientation '#{current_orientation} - will do nothing"
|
104
108
|
end
|
105
109
|
else
|
@@ -1,12 +1,16 @@
|
|
1
|
+
require 'calabash-cucumber/utils/logging'
|
2
|
+
|
1
3
|
module Calabash
|
2
4
|
module Cucumber
|
3
5
|
module StatusBarHelpers #=> Map
|
4
6
|
|
7
|
+
include Calabash::Cucumber::Logging
|
8
|
+
|
5
9
|
def device_orientation(force_down=false)
|
6
10
|
res = map(nil, :orientation, :device).first
|
7
11
|
|
8
12
|
if ['face up', 'face down'].include?(res)
|
9
|
-
if
|
13
|
+
if full_console_logging?
|
10
14
|
if force_down
|
11
15
|
puts "WARN found orientation '#{res}' - will rotate to force orientation to 'down'"
|
12
16
|
end
|
@@ -2,11 +2,14 @@ require 'edn'
|
|
2
2
|
require 'json'
|
3
3
|
# required for ruby 1.8
|
4
4
|
require 'enumerator'
|
5
|
+
require 'calabash-cucumber/utils/logging'
|
5
6
|
|
6
7
|
module Calabash
|
7
8
|
module Cucumber
|
8
9
|
module UIA
|
9
10
|
|
11
|
+
include Calabash::Cucumber::Logging
|
12
|
+
|
10
13
|
def uia(command,options={})
|
11
14
|
res = http({:method => :post, :path => 'uia'}, {:command => command}.merge(options))
|
12
15
|
res = JSON.parse(res)
|
@@ -16,15 +19,6 @@ module Calabash
|
|
16
19
|
res['results'].first
|
17
20
|
end
|
18
21
|
|
19
|
-
def uia_tap_server(query, options={})
|
20
|
-
res = http({:method => :post, :path => 'uia-tap'}, {:query => query}.merge(options))
|
21
|
-
res = JSON.parse(res)
|
22
|
-
if res['outcome'] != 'SUCCESS'
|
23
|
-
raise "uia-tap action failed because: #{res['reason']}\n#{res['details']}"
|
24
|
-
end
|
25
|
-
res['results'].first
|
26
|
-
end
|
27
|
-
|
28
22
|
def uia_query(*queryparts)
|
29
23
|
#TODO escape '\n etc in query
|
30
24
|
uia_handle_command(:query, queryparts)
|
@@ -201,7 +195,7 @@ module Calabash
|
|
201
195
|
end
|
202
196
|
end
|
203
197
|
command = "#{js_cmd}.#{js_args.join('.')}"
|
204
|
-
if
|
198
|
+
if debug_logging?
|
205
199
|
puts 'Sending UIA command'
|
206
200
|
puts command
|
207
201
|
end
|
@@ -212,7 +206,7 @@ module Calabash
|
|
212
206
|
|
213
207
|
def uia_handle_command(cmd, *query_args)
|
214
208
|
command = uia_serialize_command(cmd, *query_args)
|
215
|
-
if
|
209
|
+
if debug_logging?
|
216
210
|
puts 'Sending UIA command'
|
217
211
|
puts command
|
218
212
|
end
|
@@ -270,7 +264,7 @@ module Calabash
|
|
270
264
|
end
|
271
265
|
|
272
266
|
def uia_result(s)
|
273
|
-
if
|
267
|
+
if debug_logging?
|
274
268
|
puts 'Result'
|
275
269
|
p s
|
276
270
|
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
|
2
|
+
module Calabash
|
3
|
+
module Cucumber
|
4
|
+
|
5
|
+
# internal logging methods for calabash-ios gem
|
6
|
+
module Logging
|
7
|
+
|
8
|
+
# controls the the kind of information calabash logs
|
9
|
+
#
|
10
|
+
# this is considered one level above debug logging - maybe we should call
|
11
|
+
# the info log level.
|
12
|
+
#
|
13
|
+
# @return [Boolean] +true+ if the <tt>CALABASH_FULL_CONSOLE_OUTPUT</tt> is set to
|
14
|
+
# '1'
|
15
|
+
def full_console_logging?
|
16
|
+
ENV['CALABASH_FULL_CONSOLE_OUTPUT'] == '1'
|
17
|
+
end
|
18
|
+
|
19
|
+
# controls whether or not calabash logs debug information
|
20
|
+
#
|
21
|
+
# @return [Boolean] +true+ if the <tt>DEBUG</tt> is set to '1'
|
22
|
+
def debug_logging?
|
23
|
+
ENV['DEBUG'] == '1'
|
24
|
+
end
|
25
|
+
|
26
|
+
# prints a blue/cyan warning message
|
27
|
+
# @param [String] msg the message to print
|
28
|
+
def calabash_warn(msg)
|
29
|
+
begin
|
30
|
+
warn "\033[34m\nWARN: #{msg}\033[0m"
|
31
|
+
rescue
|
32
|
+
warn "\nWARN: #{msg}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# prints a green info message
|
37
|
+
# @param [String] msg the message to print
|
38
|
+
def calabash_info(msg)
|
39
|
+
begin
|
40
|
+
puts "\033[32m\nINFO: #{msg}\033[0m"
|
41
|
+
rescue
|
42
|
+
puts "\nINFO: #{msg}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# controls printing of deprecation warnings
|
47
|
+
#
|
48
|
+
# to inhibit deprecation message set this to '1'
|
49
|
+
#
|
50
|
+
# inhibiting deprecation messages is not recommend
|
51
|
+
CALABASH_NO_DEPRECATION = ENV['CALABASH_NO_DEPRECATION'] || '0'
|
52
|
+
|
53
|
+
# returns +true+ if the <tt>CALABASH_NO_DEPRECATION</tt> variable is set
|
54
|
+
# to +1+
|
55
|
+
def no_deprecation_warnings?
|
56
|
+
ENV['CALABASH_NO_DEPRECATION'] == '1'
|
57
|
+
end
|
58
|
+
|
59
|
+
# prints a deprecated message that includes the line number
|
60
|
+
#
|
61
|
+
# if ENV['CALABASH_NO_DEPRECATION'] == '1' then this method is a nop
|
62
|
+
#
|
63
|
+
# @param [String] version indicates when the feature was deprecated
|
64
|
+
# @param [String] msg deprecation message (possibly suggesting alternatives)
|
65
|
+
# @param [Symbol] type { :warn | :pending } - :pending will raise a
|
66
|
+
# cucumber pending exception
|
67
|
+
def _deprecated(version, msg, type)
|
68
|
+
allowed = [:pending, :warn]
|
69
|
+
unless allowed.include?(type)
|
70
|
+
raise "type '#{type}' must be on of '#{allowed}'"
|
71
|
+
end
|
72
|
+
|
73
|
+
unless no_deprecation_warnings?
|
74
|
+
|
75
|
+
if RUBY_VERSION < '2.0'
|
76
|
+
stack = Kernel.caller()[1..6].join("\n")
|
77
|
+
else
|
78
|
+
stack = Kernel.caller(0, 6)[1..-1].join("\n")
|
79
|
+
end
|
80
|
+
|
81
|
+
msg = "deprecated '#{version}' - '#{msg}'\n#{stack}"
|
82
|
+
|
83
|
+
if type.eql?(:pending)
|
84
|
+
pending(msg)
|
85
|
+
else
|
86
|
+
begin
|
87
|
+
warn "\033[34m\nWARN: #{msg}\033[0m"
|
88
|
+
rescue
|
89
|
+
warn "\nWARN: #{msg}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require 'calabash-cucumber/utils/logging'
|
2
|
+
|
3
|
+
module Calabash
|
4
|
+
module Cucumber
|
5
|
+
|
6
|
+
include Calabash::Cucumber::Logging
|
7
|
+
|
8
|
+
# module for reading and writing property list values
|
9
|
+
module PlistBuddy
|
10
|
+
|
11
|
+
# reads +key+ from +file+ and returns the result
|
12
|
+
# @param [String] key the key to inspect (may not be nil or empty)
|
13
|
+
# @param [String] file the plist to read
|
14
|
+
# @param [Hash] opts options for controlling execution
|
15
|
+
# @option opts [Boolean] :verbose (false) controls log level
|
16
|
+
# @return [nil] if +key+ does not exist
|
17
|
+
# @return [String] if the +key+ exists then the value of +key+ (error)
|
18
|
+
# @raise [ArgumentError] if nil or empty +key+
|
19
|
+
def plist_read(key, file, opts={})
|
20
|
+
if key.nil? or key.length == 0
|
21
|
+
raise(ArgumentError, "key '#{key}' must not be nil or empty")
|
22
|
+
end
|
23
|
+
cmd = build_plist_cmd(:print, {:key => key}, file)
|
24
|
+
res = execute_plist_cmd(cmd, opts)
|
25
|
+
if res == "Print: Entry, \":#{key}\", Does Not Exist"
|
26
|
+
nil
|
27
|
+
else
|
28
|
+
res
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# checks if the key exists in plist
|
33
|
+
# @param [String] key the key to inspect (may not be nil or empty)
|
34
|
+
# @param [String] file the plist to read
|
35
|
+
# @param [Hash] opts options for controlling execution
|
36
|
+
# @option opts [Boolean] :verbose (false) controls log level
|
37
|
+
# @return [Boolean] true iff the +key+ exists in plist +file+
|
38
|
+
def plist_key_exists?(key, file, opts={})
|
39
|
+
plist_read(key, file, opts) != nil
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
# replaces or creates the +value+ of +key+ in the +file+
|
44
|
+
#
|
45
|
+
# @param [String] key the key to set (may not be nil or empty)
|
46
|
+
# @param [String] type the plist type (used only when adding a value)
|
47
|
+
# @param [String] value the new value
|
48
|
+
# @param [String] file the plist to read
|
49
|
+
# @param [Hash] opts options for controlling execution
|
50
|
+
# @option opts [Boolean] :verbose (false) controls log level
|
51
|
+
# @return [Boolean] true iff the operation was successful
|
52
|
+
# @raise [ArgumentError] if nil or empty +key+
|
53
|
+
def plist_set(key, type, value, file, opts={})
|
54
|
+
default_opts = {:verbose => false}
|
55
|
+
merged = default_opts.merge(opts)
|
56
|
+
|
57
|
+
if key.nil? or key.length == 0
|
58
|
+
raise(ArgumentError, "key '#{key}' must not be nil or empty")
|
59
|
+
end
|
60
|
+
|
61
|
+
cmd_args = {:key => key,
|
62
|
+
:type => type,
|
63
|
+
:value => value}
|
64
|
+
|
65
|
+
if plist_key_exists?(key, file, merged)
|
66
|
+
cmd = build_plist_cmd(:set, cmd_args, file)
|
67
|
+
else
|
68
|
+
cmd = build_plist_cmd(:add, cmd_args, file)
|
69
|
+
end
|
70
|
+
|
71
|
+
res = execute_plist_cmd(cmd, merged)
|
72
|
+
res == ''
|
73
|
+
end
|
74
|
+
|
75
|
+
@private
|
76
|
+
|
77
|
+
# returns the path to the PlistBuddy executable
|
78
|
+
# @return [String] path to PlistBuddy
|
79
|
+
def plist_buddy
|
80
|
+
'/usr/libexec/PlistBuddy'
|
81
|
+
end
|
82
|
+
|
83
|
+
# executes +cmd+ as a shell command and returns the result
|
84
|
+
#
|
85
|
+
# @param [String] cmd shell command to execute
|
86
|
+
# @param [Hash] opts options for controlling execution
|
87
|
+
# @option opts [Boolean] :verbose (false) controls log level
|
88
|
+
# @return [Boolean] if command was successful
|
89
|
+
# @return [String] if :print'ing result, the value of the key
|
90
|
+
# @return [String] if there is an error, the output from stderr
|
91
|
+
def execute_plist_cmd(cmd, opts={})
|
92
|
+
default_opts = {:verbose => false}
|
93
|
+
merged = default_opts.merge(opts)
|
94
|
+
|
95
|
+
calabash_info(cmd) if merged[:verbose]
|
96
|
+
|
97
|
+
res = nil
|
98
|
+
# noinspection RubyUnusedLocalVariable
|
99
|
+
Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
|
100
|
+
err = stderr.read
|
101
|
+
std = stdout.read
|
102
|
+
if not err.nil? and err != ''
|
103
|
+
res = err.chomp
|
104
|
+
else
|
105
|
+
res = std.chomp
|
106
|
+
end
|
107
|
+
end
|
108
|
+
res
|
109
|
+
end
|
110
|
+
|
111
|
+
# composes a PlistBuddy command that can be executed as a shell command
|
112
|
+
#
|
113
|
+
# @param [Symbol] type should be one of [:print, :set, :add]
|
114
|
+
#
|
115
|
+
# @param [Hash] args_hash arguments used to construct plist command
|
116
|
+
# @option args_hash [String] :key (required) the plist key
|
117
|
+
# @option args_hash [String] :value (required for :set and :add) the new value
|
118
|
+
# @option args_hash [String] :type (required for :add) the new type of the value
|
119
|
+
#
|
120
|
+
# @param [String] file the plist file to interact with (must exist)
|
121
|
+
#
|
122
|
+
# @raise [RuntimeError] if +file+ does not exist
|
123
|
+
# @raise [ArgumentError] when invalid +type+ is passed
|
124
|
+
# @raise [ArgumentError] when +args_hash+ does not include required key/value pairs
|
125
|
+
#
|
126
|
+
# @return [String] a shell-ready PlistBuddy command
|
127
|
+
def build_plist_cmd(type, args_hash, file)
|
128
|
+
|
129
|
+
unless File.exist?(File.expand_path(file))
|
130
|
+
raise(RuntimeError, "plist '#{file}' does not exist - could not read")
|
131
|
+
end
|
132
|
+
|
133
|
+
case type
|
134
|
+
when :add
|
135
|
+
value_type = args_hash[:type]
|
136
|
+
unless value_type
|
137
|
+
raise(ArgumentError, ':value_type is a required key for :add command')
|
138
|
+
end
|
139
|
+
allowed_value_types = ['string', 'bool', 'real', 'integer']
|
140
|
+
unless allowed_value_types.include?(value_type)
|
141
|
+
raise(ArgumentError, "expected '#{value_type}' to be one of '#{allowed_value_types}'")
|
142
|
+
end
|
143
|
+
value = args_hash[:value]
|
144
|
+
unless value
|
145
|
+
raise(ArgumentError, ':value is a required key for :add command')
|
146
|
+
end
|
147
|
+
key = args_hash[:key]
|
148
|
+
unless key
|
149
|
+
raise(ArgumentError, ':key is a required key for :add command')
|
150
|
+
end
|
151
|
+
cmd_part = "\"Add :#{key} #{value_type} #{value}\""
|
152
|
+
when :print
|
153
|
+
key = args_hash[:key]
|
154
|
+
unless key
|
155
|
+
raise(ArgumentError, ':key is a required key for :print command')
|
156
|
+
end
|
157
|
+
cmd_part = "\"Print :#{key}\""
|
158
|
+
when :set
|
159
|
+
value = args_hash[:value]
|
160
|
+
unless value
|
161
|
+
raise(ArgumentError, ':value is a required key for :set command')
|
162
|
+
end
|
163
|
+
key = args_hash[:key]
|
164
|
+
unless key
|
165
|
+
raise(ArgumentError, ':key is a required key for :set command')
|
166
|
+
end
|
167
|
+
cmd_part = "\"Set :#{key} #{value}\""
|
168
|
+
else
|
169
|
+
cmds = [:add, :print, :set]
|
170
|
+
raise(ArgumentError, "expected '#{type}' to be one of '#{cmds}'")
|
171
|
+
end
|
172
|
+
|
173
|
+
"#{plist_buddy} -c #{cmd_part} \"#{file}\""
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,250 @@
|
|
1
|
+
require 'calabash-cucumber/utils/xctools'
|
2
|
+
require 'calabash-cucumber/utils/plist_buddy'
|
3
|
+
require 'sim_launcher'
|
4
|
+
|
5
|
+
module Calabash
|
6
|
+
module Cucumber
|
7
|
+
|
8
|
+
# methods for checking and setting simulator accessibility
|
9
|
+
module SimulatorAccessibility
|
10
|
+
|
11
|
+
include Calabash::Cucumber::XcodeTools
|
12
|
+
include Calabash::Cucumber::PlistBuddy
|
13
|
+
|
14
|
+
# quits the iOS Simulator
|
15
|
+
#
|
16
|
+
# ATM there can only be only simulator open at a time, so simply doing
|
17
|
+
# what the sim_launcher gem does:
|
18
|
+
#
|
19
|
+
# def quit_simulator
|
20
|
+
# `echo 'application "iPhone Simulator" quit' | osascript`
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# works. I am not sure if we will ever be able to launch more than one
|
24
|
+
# simulator, but in case we can, this method will quit the simulator
|
25
|
+
# that is indicated by +xcode-select+ or +DEVELOPER_DIR+.
|
26
|
+
def quit_simulator
|
27
|
+
dev_dir = xcode_developer_dir
|
28
|
+
system "/usr/bin/osascript -e 'tell application \"#{dev_dir}/Platforms/iPhoneSimulator.platform/Developer/Applications/iPhone Simulator.app\" to quit'"
|
29
|
+
end
|
30
|
+
|
31
|
+
# launches the iOS Simulator indicated by +xcode-select+ or +DEVELOPER_DIR+
|
32
|
+
def launch_simulator
|
33
|
+
dev_dir = xcode_developer_dir
|
34
|
+
system "open -a \"#{dev_dir}/Platforms/iPhoneSimulator.platform/Developer/Applications/iPhone Simulator.app\""
|
35
|
+
end
|
36
|
+
|
37
|
+
# resets the simulator content and settings. it is analogous to touching
|
38
|
+
# the menu item.
|
39
|
+
#
|
40
|
+
# it works by deleting the following directories:
|
41
|
+
#
|
42
|
+
# * ~/Library/Application Support/iPhone Simulator/Library
|
43
|
+
# * ~/Library/Application Support/iPhone Simulator/Library/<sdk>[-64]
|
44
|
+
#
|
45
|
+
# and relaunching the iOS Simulator which will recreate the Library
|
46
|
+
# directory and the latest SDK directory.
|
47
|
+
def reset_simulator_content_and_settings
|
48
|
+
quit_simulator
|
49
|
+
sim_lib_path = File.join(simulator_app_support_dir(), 'Library')
|
50
|
+
FileUtils.rm_rf(sim_lib_path)
|
51
|
+
simulator_support_sdk_dirs.each do |dir|
|
52
|
+
FileUtils.rm_rf(dir)
|
53
|
+
end
|
54
|
+
|
55
|
+
launch_simulator
|
56
|
+
|
57
|
+
# this is tricky because we need to wait for the simulator to recreate
|
58
|
+
# the directories. specifically, we need the Accessibility plist to be
|
59
|
+
# exist so subsequent calabash launches will be able to enable
|
60
|
+
# accessibility.
|
61
|
+
#
|
62
|
+
# the directories take ~3.0 - ~5.0 to create.
|
63
|
+
counter = 0
|
64
|
+
loop do
|
65
|
+
break if counter == 80
|
66
|
+
dirs = simulator_support_sdk_dirs
|
67
|
+
if dirs.count == 0
|
68
|
+
sleep(0.2)
|
69
|
+
else
|
70
|
+
break if dirs.all? { |dir|
|
71
|
+
plist = File.expand_path("#{dir}/Library/Preferences/com.apple.Accessibility.plist")
|
72
|
+
File.exists?(plist)
|
73
|
+
}
|
74
|
+
sleep(0.2)
|
75
|
+
end
|
76
|
+
counter = counter + 1
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# enables accessibility on any existing iOS Simulator by adjusting the
|
81
|
+
# simulator's Library/Preferences/com.apple.Accessibility.plist contents.
|
82
|
+
#
|
83
|
+
# a simulator 'exists' if has an Application Support directory. for
|
84
|
+
# example, the 6.1, 7.0.3-64, and 7.1 simulators exist if the following
|
85
|
+
# directories are present:
|
86
|
+
#
|
87
|
+
# ~/Library/Application Support/iPhone Simulator/Library/6.1
|
88
|
+
# ~/Library/Application Support/iPhone Simulator/Library/7.0.3-64
|
89
|
+
# ~/Library/Application Support/iPhone Simulator/Library/7.1
|
90
|
+
#
|
91
|
+
# this method also hides the AXInspector.
|
92
|
+
# @param [Hash] opts controls the behavior of the method
|
93
|
+
# @option opts [Boolean] :verbose controls logging output
|
94
|
+
# @return [Boolean] true iff enabling accessibility worked on all sdk
|
95
|
+
# directories
|
96
|
+
def enable_accessibility_on_simulators(opts={})
|
97
|
+
results = simulator_support_sdk_dirs.map do |dir|
|
98
|
+
enable_accessibility_in_sdk_dir(dir, opts)
|
99
|
+
end
|
100
|
+
results.all? { |elm| elm }
|
101
|
+
end
|
102
|
+
|
103
|
+
@private
|
104
|
+
|
105
|
+
# enables accessibility on the simulator indicated by
|
106
|
+
# +sim_app_support_sdk_dir+.
|
107
|
+
#
|
108
|
+
# WARNING: this will quit the simulator
|
109
|
+
#
|
110
|
+
# path = '~/Library/Application Support/iPhone Simulator/Library/6.1'
|
111
|
+
# enable_accessibility_in_sdk_dir(path)
|
112
|
+
#
|
113
|
+
# this method also hides the AXInspector.
|
114
|
+
#
|
115
|
+
# if the Library/Preferences/com.apple.Accessibility.plist does not exist,
|
116
|
+
# this method returns false.
|
117
|
+
#
|
118
|
+
# @see enable_accessibility_on_simulators for the public API.
|
119
|
+
#
|
120
|
+
# @param [String] sim_app_support_sdk_dir the directory where the
|
121
|
+
# Library/Preferences/com.apple.Accessibility.plist can be found.
|
122
|
+
#
|
123
|
+
# @param [Hash] opts controls the behavior of the method
|
124
|
+
# @option opts [Boolean] :verbose controls logging output
|
125
|
+
# @return [Boolean] iff the plist exists and the plist was successfully
|
126
|
+
# updated.
|
127
|
+
def enable_accessibility_in_sdk_dir(sim_app_support_sdk_dir, opts={})
|
128
|
+
default_opts = {:verbose => false}
|
129
|
+
merged = default_opts.merge(opts)
|
130
|
+
|
131
|
+
plist_path = File.expand_path("#{sim_app_support_sdk_dir}/Library/Preferences/com.apple.Accessibility.plist")
|
132
|
+
|
133
|
+
verbose = merged[:verbose]
|
134
|
+
|
135
|
+
sdk = File.basename(sim_app_support_sdk_dir)
|
136
|
+
msgs = ["cannot enable accessibility for #{sdk} SDK"]
|
137
|
+
unless File.exists?(plist_path)
|
138
|
+
if verbose
|
139
|
+
msgs << "expected plist to exist at #{plist_path}"
|
140
|
+
calabash_warn(msgs.join("\n"))
|
141
|
+
end
|
142
|
+
return false
|
143
|
+
end
|
144
|
+
|
145
|
+
quit_simulator
|
146
|
+
|
147
|
+
hash = accessibility_properties_hash()
|
148
|
+
|
149
|
+
unless plist_set(hash[:access_enabled], 'bool', 'true', plist_path)
|
150
|
+
if verbose
|
151
|
+
msgs << "could not set '#{hash[:access_enabled]}' to YES"
|
152
|
+
calabash_warn(msgs.join("\n"))
|
153
|
+
end
|
154
|
+
return false
|
155
|
+
end
|
156
|
+
|
157
|
+
unless plist_set(hash[:app_access_enabled], 'bool', 'true', plist_path)
|
158
|
+
if verbose
|
159
|
+
msgs << "could not set '#{hash[:app_access_enabled]}' to YES"
|
160
|
+
calabash_warn(msgs.join("\n"))
|
161
|
+
end
|
162
|
+
return false
|
163
|
+
end
|
164
|
+
|
165
|
+
unless plist_set(hash[:automation_enabled], 'bool', 'true', plist_path)
|
166
|
+
if verbose
|
167
|
+
msgs << "could not set '#{hash[:automation_enabled]}' to YES"
|
168
|
+
calabash_warn(msgs.join("\n"))
|
169
|
+
end
|
170
|
+
return false
|
171
|
+
end
|
172
|
+
|
173
|
+
unless plist_set(hash[:inspector_showing], 'bool', 'false', plist_path)
|
174
|
+
if verbose
|
175
|
+
msgs << "could not set '#{hash[:inspector_showing]}' to NO"
|
176
|
+
calabash_warn(msgs.join("\n"))
|
177
|
+
end
|
178
|
+
return false
|
179
|
+
end
|
180
|
+
|
181
|
+
unless plist_set(hash[:inspector_full_size], 'bool', 'false', plist_path)
|
182
|
+
if verbose
|
183
|
+
msgs << "could not set '#{hash[:inspector_full_size]}' to NO"
|
184
|
+
calabash_warn(msgs.join("\n"))
|
185
|
+
end
|
186
|
+
return false
|
187
|
+
end
|
188
|
+
|
189
|
+
res = plist_set(hash[:inspector_frame], 'string', '{{270, -13}, {276, 166}}', plist_path)
|
190
|
+
unless res
|
191
|
+
if verbose
|
192
|
+
msgs << "could not set '#{hash[:inspector_frame]}'"
|
193
|
+
calabash_warn(msgs.join("\n"))
|
194
|
+
end
|
195
|
+
end
|
196
|
+
res
|
197
|
+
end
|
198
|
+
|
199
|
+
|
200
|
+
# a hash table of the accessibility properties that control whether or not
|
201
|
+
# accessibility is enabled and whether the AXInspector is visible.
|
202
|
+
# @return [Hash] table of accessibility properties found in the
|
203
|
+
# Library/Preferences/com.apple.Accessibility.plist
|
204
|
+
def accessibility_properties_hash
|
205
|
+
{
|
206
|
+
# this is required
|
207
|
+
:access_enabled => 'AccessibilityEnabled',
|
208
|
+
# i _think_ this is legacy
|
209
|
+
:app_access_enabled => 'ApplicationAccessibilityEnabled',
|
210
|
+
|
211
|
+
# i don't know what this does
|
212
|
+
:automation_enabled => 'AutomationEnabled',
|
213
|
+
|
214
|
+
# determines if the Accessibility Inspector is showing
|
215
|
+
:inspector_showing => 'AXInspectorEnabled',
|
216
|
+
# controls if the Accessibility Inspector is expanded or not expanded
|
217
|
+
:inspector_full_size => 'AXInspector.enabled',
|
218
|
+
# controls the frame of the Accessibility Inspector
|
219
|
+
# this is a 'string' => {{0, 0}, {276, 166}}
|
220
|
+
:inspector_frame => 'AXInspector.frame'
|
221
|
+
}
|
222
|
+
end
|
223
|
+
|
224
|
+
# the absolute path the the iPhone Simulator Application Support directory
|
225
|
+
# @return [String] absolute path
|
226
|
+
def simulator_app_support_dir
|
227
|
+
File.expand_path('~/Library/Application Support/iPhone Simulator')
|
228
|
+
end
|
229
|
+
|
230
|
+
# returns a list of absolute paths the existing simulator directories.
|
231
|
+
#
|
232
|
+
# a simulator 'exists' if has an Application Support directory. for
|
233
|
+
# example, the 6.1, 7.0.3-64, and 7.1 simulators exist if the following
|
234
|
+
# directories are present:
|
235
|
+
#
|
236
|
+
# ~/Library/Application Support/iPhone Simulator/Library/6.1
|
237
|
+
# ~/Library/Application Support/iPhone Simulator/Library/7.0.3-64
|
238
|
+
# ~/Library/Application Support/iPhone Simulator/Library/7.1
|
239
|
+
#
|
240
|
+
# @return[Array<String>] a list of absolute paths to simulator directories
|
241
|
+
def simulator_support_sdk_dirs
|
242
|
+
sim_app_support_path = simulator_app_support_dir()
|
243
|
+
Dir.glob("#{sim_app_support_path}/*").select { |path|
|
244
|
+
path =~ /(\d)\.(\d)\.?(\d)?(-64)?/
|
245
|
+
}
|
246
|
+
end
|
247
|
+
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|