Class: Calabash::Cucumber::Launcher
- Inherits:
-
Object
- Object
- Calabash::Cucumber::Launcher
- Includes:
- Logging, SimulatorAccessibility
- Defined in:
- lib/calabash-cucumber/launcher.rb
Overview
Used to launch apps for testing in iOS Simulator or on iOS Devices. By default it uses Apple’s ‘instruments` process to launch your app, but has legacy support for using `sim_launcher`.
### Accessing the current launcher from ruby.
If you need a reference to the current launcher in your ruby code. This is usually not required, but might be useful in ‘support/01_launch.rb`.
‘Calabash::Cucumber::Launcher.launcher`
### Attaching to the current launcher in a console
If Calabash already running and you want to attach to the current launcher, use ‘console_attach`. This is useful when a cucumber Scenario has failed and you want to query the current state of the app.
-
**Pro Tip:** set the ‘NO_STOP` environmental variable to 1 so calabash does
not exit the simulator when a Scenario fails.
Constant Summary collapse
- KNOWN_PRIVACY_SETTINGS =
A hash of known privacy settings that calabash can control.
{:photos => 'kTCCServicePhotos', :calendar => 'kTCCServiceCalendar', :address_book => 'kTCCServiceAddressBook'}
Instance Attribute Summary collapse
-
#actions ⇒ Object
writeonly
Sets the attribute actions.
-
#device ⇒ Object
Returns the value of attribute device.
-
#launch_args ⇒ Object
Returns the value of attribute launch_args.
-
#run_loop ⇒ Object
Returns the value of attribute run_loop.
-
#simulator_launcher ⇒ Object
Returns the value of attribute simulator_launcher.
Class Method Summary collapse
- .attach ⇒ Object
-
.instruments? ⇒ Boolean
Are we running using instruments?.
-
.launcher ⇒ Calabash::Cucumber::Launcher
Get a reference to the current launcher (instantiates a new one if needed).
-
.launcher_if_used ⇒ Calabash::Cucumber::Launcher
Get a reference to the current launcher (does not instantiate a new one if unset).
Instance Method Summary collapse
- #attach(options = {}) ⇒ Object
-
#ios_major_version ⇒ String
“Major” component of the current iOS version of the device.
-
#ios_version ⇒ String
the current iOS version of the device.
-
#relaunch(args = {}) ⇒ Object
Launches your app on the connected device or simulator.
-
#reset_app_jail(sdk = nil, path = nil) ⇒ Object
deprecated
Deprecated.
0.10.0 Replaced with #reset_app_sandbox.
-
#reset_app_sandbox(opts = {}) ⇒ Object
Resets the app’s content and settings by deleting the following directories from application sandbox:.
-
#reset_simulator ⇒ Object
Erases the contents and setting for every available simulator.
-
#server_version_from_server ⇒ String
queries the server for its version.
Methods included from SimulatorAccessibility
#launch_simulator, #quit_simulator, #reset_simulator_content_and_settings
Methods included from Logging
#calabash_info, #calabash_warn
Instance Attribute Details
#actions=(value) ⇒ Object
Sets the attribute actions
55 56 57 |
# File 'lib/calabash-cucumber/launcher.rb', line 55 def actions=(value) @actions = value end |
#device ⇒ Object
Returns the value of attribute device.
54 55 56 |
# File 'lib/calabash-cucumber/launcher.rb', line 54 def device @device end |
#launch_args ⇒ Object
Returns the value of attribute launch_args.
56 57 58 |
# File 'lib/calabash-cucumber/launcher.rb', line 56 def launch_args @launch_args end |
#run_loop ⇒ Object
Returns the value of attribute run_loop.
53 54 55 |
# File 'lib/calabash-cucumber/launcher.rb', line 53 def run_loop @run_loop end |
#simulator_launcher ⇒ Object
Returns the value of attribute simulator_launcher.
57 58 59 |
# File 'lib/calabash-cucumber/launcher.rb', line 57 def simulator_launcher @simulator_launcher end |
Class Method Details
.attach ⇒ Object
92 93 94 95 96 |
# File 'lib/calabash-cucumber/launcher.rb', line 92 def self.attach l = launcher return l if l && l.active? l.attach end |
.instruments? ⇒ Boolean
Are we running using instruments?
159 160 161 162 163 |
# File 'lib/calabash-cucumber/launcher.rb', line 159 def self.instruments? l = launcher_if_used return false unless l l.instruments? end |
.launcher ⇒ Calabash::Cucumber::Launcher
Get a reference to the current launcher (instantiates a new one if needed). Usually we use a singleton launcher throughout a test run.
167 168 169 |
# File 'lib/calabash-cucumber/launcher.rb', line 167 def self.launcher @@launcher ||= Calabash::Cucumber::Launcher.new end |
.launcher_if_used ⇒ Calabash::Cucumber::Launcher
Get a reference to the current launcher (does not instantiate a new one if unset). Usually we use a singleton launcher throughout a test run.
174 175 176 |
# File 'lib/calabash-cucumber/launcher.rb', line 174 def self.launcher_if_used @@launcher end |
Instance Method Details
#attach(options = {}) ⇒ Object
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/calabash-cucumber/launcher.rb', line 99 def attach(={}) = {:max_retry => 1, :timeout => 10, :uia_strategy => nil} = .merge() if calabash_no_launch? self.actions= Calabash::Cucumber::PlaybackActions.new return end # :host is is a special case and requires reading information from a cache. = [:uia_strategy] if == :host self.run_loop = RunLoop::HostCache.default.read return self end # Sets the device attribute. ensure_connectivity([:max_retry], [:timeout]) # The default strategy for iOS 8 devices is :host. if .nil? && self.device.ios_major_version > '8' self.run_loop = RunLoop::HostCache.default.read return self end pids_str = `ps x -o pid,command | grep -v grep | grep "instruments" | awk '{printf "%s,", $1}'` pids = pids_str.split(',').map { |pid| pid.to_i } pid = pids.first run_loop = {} if pid run_loop[:pid] = pid self.actions= Calabash::Cucumber::InstrumentsActions.new else self.actions= Calabash::Cucumber::PlaybackActions.new end if run_loop[:uia_strategy] = [:uia_strategy] else run_loop[:uia_strategy] = :preferences end self.run_loop = run_loop major = self.device.ios_major_version if major.to_i >= 7 && self.actions.is_a?(Calabash::Cucumber::PlaybackActions) puts "\n\n WARNING \n\n" puts 'Warning Trying to connect to simulator that was not launched by Calabash/instruments.' puts 'To fix this you must let Calabash or instruments launch the app.' puts 'Query will work, but gestures will not.' puts "\n\n WARNING \n\n" puts 'Please read: https://github.com/calabash/calabash-ios/wiki/A0-UIAutomation---instruments-problems' end self end |
#ios_major_version ⇒ String
“Major” component of the current iOS version of the device
180 181 182 183 184 185 186 |
# File 'lib/calabash-cucumber/launcher.rb', line 180 def ios_major_version # pinging the app will set self.device ping_app if self.device.nil? # guard against Runtime errors return nil if device.nil? or device.ios_version.nil? device.ios_major_version end |
#ios_version ⇒ String
the current iOS version of the device
190 191 192 193 |
# File 'lib/calabash-cucumber/launcher.rb', line 190 def ios_version return nil if device.nil? device.ios_version end |
#relaunch(args = {}) ⇒ Object
an important part of relaunch behavior is controlled by environment variables, specified below
Launches your app on the connected device or simulator. Stops the app if it is already running. ‘relaunch` does a lot of error detection and handling to reliably start the app and test. Instruments (particularly the cli) has stability issues which we workaround by restarting the simulator process and checking that UIAutomation is correctly attaching.
Takes optional args to specify details of the launch (e.g. device or simulator, sdk version, target device, launch method…). The two most important environment variables are ‘DEVICE_TARGET` and `APP_BUNDLE_PATH`.
-
‘DEVICE_TARGET` controls which device you’re running on. To see the options run: ‘instruments -s devices`. In addition you can specify `DEVICE_TARGET=device` to run on a (unique) usb-connected device.
-
‘APP_BUNDLE_PATH` controls which `.app` bundle to launch in simulator (don’t use for on-device testing, instead use ‘BUNDLE_ID`).
-
‘BUNDLE_ID` used with `DEVICE_TARGET=device` to specify which app to launch on device
-
‘DEBUG` - set to “1” to obtain debug info (typically used to debug launching, UIAutomation and other issues)
-
‘DEBUG_HTTP` - set to “1” to show raw HTTP traffic
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 |
# File 'lib/calabash-cucumber/launcher.rb', line 528 def relaunch(args={}) #TODO stopping is currently broken, but this works anyway because instruments stop the process before relaunching RunLoop.stop(run_loop) if run_loop # @todo Don't overwrite the _args_ parameter! args = default_launch_args.merge(args) # RunLoop::Core.run_with_options can reuse the SimControl instance. Many # of the Xcode tool calls, like instruments -s templates, take a long time # to execute. The SimControl instance has XCTool attribute which caches # the results of many of these time-consuming calls so they only need to # be called 1 time per launch. # @todo Use SimControl in Launcher in place of methods like simulator_target? args[:sim_control] = RunLoop::SimControl.new if args[:app] if !File.exist?(args[:app]) raise "Unable to find app bundle at #{args[:app]}. It should be an iOS Simulator build (typically a *.app directory)." end end args[:app] = args[:app] || args[:bundle_id] || app_path || detect_app_bundle_from_args(args) if args[:app] if File.directory?(args[:app]) args[:app] = File.(args[:app]) else # args[:app] is not a directory so must be a bundle id if simulator_target?(args) ## bundle id set, but simulator target args[:app] = app_path || detect_app_bundle_from_args(args) end end end unless args[:app] if simulator_target?(args) device_xamarin_build_dir = 'iPhoneSimulator' else device_xamarin_build_dir = 'iPhone' end args[:app] = self.simulator_launcher.app_bundle_or_raise(app_path, device_xamarin_build_dir) end args[:bundle_id] ||= detect_bundle_id_from_app_bundle(args) args[:device] ||= detect_device_from_args(args) if simulator_target?(args) and args[:reset] # attempt to find the sdk version from the :device_target sdk = sdk_version_for_simulator_target(args) # *** LEGACY SUPPORT *** # If DEVICE_TARGET has not been set and is not a device UDID, then # :device_target will be 'simulator'. In that case, we cannot know what # SDK version of the app sandbox we should reset. The user _might_ give # us a hint with SDK_VERSION, but we want to deprecate that variable ASAP. # # If passed a nil SDK arg, reset_app_sandbox will reset the _latest_ SDK. # This is not good, because this is probably _not_ the SDK that should be # reset. Our only option is to reset every sandbox for all SDKs by # passing :sdk => :all to reset_app_sandbox. if sdk.nil? and args[:device_target] == 'simulator' sdk = :all end reset_app_sandbox({:sdk => sdk, :path => args[:app], :udid => args[:udid], :sim_control => args[:sim_control]}) end if args[:privacy_settings] if simulator_target?(args) update_privacy_settings(args[:bundle_id], args[:privacy_settings]) else #Not supported on device puts 'Warning: :privacy_settings not supported on device' end end use_dylib = args[:inject_dylib] if use_dylib # User passed a Boolean, not a file. if use_dylib.is_a?(TrueClass) if simulator_target?(args) args[:inject_dylib] = Calabash::Dylibs.path_to_sim_dylib else args[:inject_dylib] = Cucumber::Dylibs.path_to_device_dylib end else unless File.exist? use_dylib raise "Dylib does not exist at path: '#{use_dylib}'" end end end if run_with_instruments?(args) # Patch for bug in Xcode 6 GM + iOS 8 device testing. # http://openradar.appspot.com/radar?id=5891145586442240 uia_strategy = default_uia_strategy(args, args[:sim_control]) args[:uia_strategy] ||= uia_strategy calabash_info "Using uia strategy: '#{args[:uia_strategy]}'" if debug_logging? self.run_loop = new_run_loop(args) self.actions= Calabash::Cucumber::InstrumentsActions.new else # run with sim launcher self.actions= Calabash::Cucumber::PlaybackActions.new # why not just pass args - AFAICT args[:app] == app_path? self.simulator_launcher.relaunch(app_path, sdk_version(), args) end self.launch_args = args unless args[:calabash_lite] ensure_connectivity # skip compatibility check if injecting dylib unless args.fetch(:inject_dylib, false) check_server_gem_compatibility end end end |
#reset_app_jail(sdk = nil, path = nil) ⇒ Object
0.10.0 Replaced with #reset_app_sandbox.
Reset the app sandbox for a device.
197 198 199 200 201 |
# File 'lib/calabash-cucumber/launcher.rb', line 197 def reset_app_jail(sdk=nil, path=nil) # will be deprecated in a future version #_deprecated('0.10.0', 'use reset_app_sandbox instead', :warn) reset_app_sandbox({:sdk => sdk, :path => path}) end |
#reset_app_sandbox(opts = {}) ⇒ Object
It is not recommended that you call this method directly. See the examples below for how use the ‘RESET_BETWEEN_SCENARIOS` environmental variable to reset the app sandbox.
This method is only available for the iOS Simulator.
Generates a warning if called when targeting a physical device and otherwise has no effect.
When testing against the Xamarin Test Cloud, this method is never called. Use the ‘RESET_BETWEEN_SCENARIOS` environmental variable. See the examples.
Resets the app’s content and settings by deleting the following directories from application sandbox:
-
Library
-
Documents
-
tmp
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 |
# File 'lib/calabash-cucumber/launcher.rb', line 265 def reset_app_sandbox(opts={}) if device_target? calabash_warn("calling 'reset_app_sandbox' when targeting a device.") return end default_opts = {:sdk => nil, :path => nil} merged_opts = default_opts.merge opts sim_control = opts.fetch(:sim_control, RunLoop::SimControl.new) if sim_control.xcode_version_gte_6? default_sim = RunLoop::Core.default_simulator(sim_control.xctools) name_or_udid = merged_opts[:udid] || ENV['DEVICE_TARGET'] || default_sim target_simulator = nil sim_control.simulators.each do |device| instruments_launch_name = "#{device.name} (#{device.version.to_s} Simulator)" if instruments_launch_name == name_or_udid or device.udid == name_or_udid target_simulator = device end end if target_simulator.nil? raise "Could not find a simulator that matches '#{name_or_udid}'" end sim_control.reset_sim_content_and_settings({:sim_udid => target_simulator.udid}) else sdk ||= merged_opts[:sdk] || sdk_version || self.simulator_launcher.sdk_detector.latest_sdk_version path ||= merged_opts[:path] || self.simulator_launcher.app_bundle_or_raise(app_path) app = File.basename(path) directories_for_sdk_prefix(sdk).each do |sdk_dir| app_dir = File.("#{sdk_dir}/Applications") next unless File.exists?(app_dir) bundle = `find "#{app_dir}" -type d -depth 2 -name "#{app}" | head -n 1` next if bundle.empty? # Assuming we're already clean if debug_logging? puts "Reset app state for #{bundle}" end sandbox = File.dirname(bundle) ['Library', 'Documents', 'tmp'].each do |content_dir| FileUtils.rm_rf(File.join(sandbox, content_dir)) end end end end |
#reset_simulator ⇒ Object
WARNING This is a destructive operation. You have been warned.
Erases the contents and setting for every available simulator.
For Xcode 6, this is equivalent to calling: ‘$ xcrun simctl erase` on every available simulator. For Xcode < 6, it is equivalent to touching the ’Reset Content & Settings’ menu item.
328 329 330 331 332 333 |
# File 'lib/calabash-cucumber/launcher.rb', line 328 def reset_simulator if device_target? raise "Calling 'reset_simulator' when targeting a device is not allowed" end RunLoop::SimControl.new.reset_sim_content_and_settings end |
#server_version_from_server ⇒ String
queries the server for its version.
SPECIAL: sets the @@server_version class variable to cache the server version because the server version will never change during runtime.
1025 1026 1027 1028 1029 |
# File 'lib/calabash-cucumber/launcher.rb', line 1025 def server_version_from_server return @@server_version unless @@server_version.nil? ensure_connectivity if self.device == nil @@server_version = self.device.server_version end |