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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +14 -1
  3. data/bin/calabash-ios-setup.rb +2 -4
  4. data/bin/calabash-ios-sim.rb +10 -40
  5. data/calabash-cucumber.gemspec +25 -22
  6. data/features-skeleton/support/01_launch.rb +1 -1
  7. data/lib/calabash-cucumber.rb +13 -1
  8. data/lib/calabash-cucumber/actions/instruments_actions.rb +0 -4
  9. data/lib/calabash-cucumber/actions/playback_actions.rb +0 -4
  10. data/lib/calabash-cucumber/core.rb +9 -16
  11. data/lib/calabash-cucumber/device.rb +11 -2
  12. data/lib/calabash-cucumber/environment_helpers.rb +4 -56
  13. data/lib/calabash-cucumber/ios7_operations.rb +4 -2
  14. data/lib/calabash-cucumber/keyboard_helpers.rb +6 -3
  15. data/lib/calabash-cucumber/launch/simulator_helper.rb +40 -386
  16. data/lib/calabash-cucumber/launch/simulator_launcher.rb +534 -0
  17. data/lib/calabash-cucumber/launcher.rb +172 -36
  18. data/lib/calabash-cucumber/operations.rb +3 -4
  19. data/lib/calabash-cucumber/playback_helpers.rb +15 -29
  20. data/lib/calabash-cucumber/rotation_helpers.rb +14 -10
  21. data/lib/calabash-cucumber/status_bar_helpers.rb +5 -1
  22. data/lib/calabash-cucumber/uia.rb +6 -12
  23. data/lib/calabash-cucumber/utils/logging.rb +97 -0
  24. data/lib/calabash-cucumber/utils/plist_buddy.rb +178 -0
  25. data/lib/calabash-cucumber/utils/simulator_accessibility.rb +250 -0
  26. data/lib/calabash-cucumber/utils/xctools.rb +95 -0
  27. data/lib/calabash-cucumber/version.rb +197 -2
  28. data/lib/calabash-cucumber/wait_helpers.rb +16 -20
  29. data/scripts/.irbrc +11 -6
  30. data/scripts/com.example.plist +0 -0
  31. data/scripts/launch.rb +1 -1
  32. data/spec/bin/calabash_ios_sim_spec.rb +24 -0
  33. data/spec/launcher_spec.rb +76 -0
  34. data/spec/logging_spec.rb +38 -0
  35. data/spec/plist_buddy_spec.rb +99 -0
  36. data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/Default-568h@2x.png +0 -0
  37. data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/Info.plist +0 -0
  38. data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/LPSimpleExample-cal +0 -0
  39. data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/PkgInfo +1 -0
  40. data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/en.lproj/InfoPlist.strings +0 -0
  41. data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/en.lproj/LPFirstViewController.nib +0 -0
  42. data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/en.lproj/LPFirstViewController~ipad.nib +0 -0
  43. data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/en.lproj/LPFourthViewController.nib +0 -0
  44. data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/en.lproj/LPFourthViewController~ipad.nib +0 -0
  45. data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/en.lproj/LPSecondViewController.nib +0 -0
  46. data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/en.lproj/LPSecondViewController~ipad.nib +0 -0
  47. data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/en.lproj/LPThirdViewController.nib +0 -0
  48. data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/en.lproj/LPThirdViewController~ipad.nib +0 -0
  49. data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/first.png +0 -0
  50. data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/first@2x.png +0 -0
  51. data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/second.png +0 -0
  52. data/spec/resources/enable-accessibility/LPSimpleExample-cal.app/second@2x.png +0 -0
  53. data/spec/resources/plist_buddy/com.example.plist +0 -0
  54. data/spec/resources/plist_buddy/com.testing.plist +18 -0
  55. data/spec/simulator_accessibility_spec.rb +144 -0
  56. data/spec/spec_helper.rb +31 -0
  57. data/spec/xctools_spec.rb +58 -0
  58. 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 ENV['CALABASH_FULL_CONSOLE_OUTPUT'] == '1'
22
- warn "converting '#{dir}' to ':up' - please adjust your code"
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 ENV['CALABASH_FULL_CONSOLE_OUTPUT'] == '1'
29
- warn "converting '#{dir}' to ':down' - please adjust your code"
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 ENV['CALABASH_FULL_CONSOLE_OUTPUT'] == '1'
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 ENV['CALABASH_FULL_CONSOLE_OUTPUT'] == '1'
67
- warn "Could not rotate home button to '#{dir}'."
68
- warn 'Is rotation enabled for this controller?'
69
- warn "Will return 'down'"
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 ENV['CALABASH_FULL_CONSOLE_OUTPUT'] == '1'
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 ENV['CALABASH_FULL_CONSOLE_OUTPUT'] == '1'
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 ENV['DEBUG'] == '1'
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 ENV['DEBUG'] == '1'
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 ENV['DEBUG'] == '1'
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