run_loop 2.2.4 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/run_loop/cli/instruments.rb +9 -0
- data/lib/run_loop/core.rb +2 -4
- data/lib/run_loop/core_simulator.rb +232 -115
- data/lib/run_loop/device.rb +177 -105
- data/lib/run_loop/device_agent/Frameworks.zip +0 -0
- data/lib/run_loop/device_agent/app/DeviceAgent-Runner.app.zip +0 -0
- data/lib/run_loop/device_agent/bin/iOSDeviceManager +0 -0
- data/lib/run_loop/device_agent/client.rb +113 -37
- data/lib/run_loop/device_agent/ios_device_manager.rb +9 -14
- data/lib/run_loop/device_agent/ipa/DeviceAgent-Runner.app.zip +0 -0
- data/lib/run_loop/logging.rb +1 -1
- data/lib/run_loop/process_waiter.rb +35 -4
- data/lib/run_loop/simctl.rb +2 -2
- data/lib/run_loop/version.rb +1 -1
- data/scripts/lib/on_alert.js +33 -2
- data/vendor-licenses/CocoaAsyncSocket.LICENSE +4 -0
- data/vendor-licenses/CocoaHTTPServer.LICENSE +18 -0
- data/vendor-licenses/CocoaLumberjack.LICENSE +33 -0
- data/vendor-licenses/Facebook-WebDriverAgent.LICENSE +30 -0
- data/vendor-licenses/RoutingHTTPServer.LICENSE +19 -0
- metadata +8 -4
- data/vendor-licenses/xctestctl.LICENSE +0 -32
data/lib/run_loop/device.rb
CHANGED
@@ -31,7 +31,7 @@ module RunLoop
|
|
31
31
|
# exceeded - if the default 30 seconds has passed, the
|
32
32
|
# simulator is probably stable enough for subsequent
|
33
33
|
# operations.
|
34
|
-
:timeout => RunLoop::Environment.ci? ?
|
34
|
+
:timeout => RunLoop::Environment.ci? ? 240 : 120
|
35
35
|
}
|
36
36
|
|
37
37
|
attr_reader :name
|
@@ -322,124 +322,54 @@ version: #{version}
|
|
322
322
|
end
|
323
323
|
|
324
324
|
# @!visibility private
|
325
|
-
#
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
# 3. 1 and 2 must hold for 1.5 seconds.
|
331
|
-
#
|
332
|
-
# When the simulator version is >= iOS 9, two more conditions are added to
|
333
|
-
# get past the iOS 9+ boot screen.
|
334
|
-
#
|
335
|
-
# 4. Wait for com.apple.audio.SystemSoundServer-iOS-Simulator process to
|
336
|
-
# start.
|
337
|
-
# 5. 1 and 2 must hold for 1.5 seconds.
|
338
|
-
#
|
339
|
-
# When the simulator version is >= iOS 9 and the device is an iPad another
|
340
|
-
# condition is added because simctl fails to correctly install applications;
|
341
|
-
# the app and data container exists, but Springboard does not detect them.
|
342
|
-
#
|
343
|
-
# 6. 1 and 2 must hold for 1.5 seconds.
|
344
|
-
#
|
345
|
-
# TODO needs update for Xcode 8 + iOS 10 simulators.
|
346
|
-
def simulator_wait_for_stable_state
|
347
|
-
|
348
|
-
# How long to wait between stability checks.
|
349
|
-
# Shorter than this gives false positives.
|
350
|
-
delay = 0.5
|
351
|
-
|
352
|
-
# How many times to wait for stable state.
|
353
|
-
max_stable_count = 3
|
354
|
-
|
355
|
-
# How long to wait for iOS 9 boot screen.
|
356
|
-
boot_screen_wait_options = {
|
357
|
-
:max_boot_screen_wait => 10,
|
358
|
-
:raise_on_timeout => false
|
359
|
-
}
|
360
|
-
|
361
|
-
# How much additional time to wait for iOS 9+ iPads.
|
362
|
-
#
|
363
|
-
# Installing and launching on iPads is problematic.
|
364
|
-
# Sometimes the app is installed, but SpringBoard does
|
365
|
-
# not recognize that the app is installed even though
|
366
|
-
# simctl says that it is.
|
367
|
-
additional_ipad_delay = delay * 2
|
368
|
-
|
369
|
-
# Adjust for CI environments
|
370
|
-
if RunLoop::Environment.ci?
|
371
|
-
max_stable_count = 5
|
372
|
-
boot_screen_wait_options[:max_boot_screen_wait] = 20
|
373
|
-
additional_ipad_delay = delay * 4
|
374
|
-
end
|
375
|
-
|
376
|
-
# iOS 9 simulators have an additional boot screen.
|
377
|
-
is_gte_ios9 = version >= RunLoop::Version.new('9.0')
|
378
|
-
|
379
|
-
# Xcode 8 simulators do not need to wait for log file
|
380
|
-
is_xcode8 = RunLoop::Xcode.new.version_gte_8?
|
325
|
+
# In megabytes
|
326
|
+
def simulator_size_on_disk
|
327
|
+
data_path = File.join(simulator_root_dir, 'data')
|
328
|
+
RunLoop::Directory.size(data_path, :mb)
|
329
|
+
end
|
381
330
|
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
is_ipad = simulator_is_ipad?
|
331
|
+
# @!visibility private
|
332
|
+
def simulator_wait_for_stable_state
|
333
|
+
required = simulator_required_child_processes
|
386
334
|
|
387
335
|
timeout = SIM_STABLE_STATE_OPTIONS[:timeout]
|
388
336
|
now = Time.now
|
389
337
|
poll_until = now + timeout
|
390
338
|
|
391
339
|
RunLoop.log_debug("Waiting for simulator to stabilize with timeout: #{timeout} seconds")
|
340
|
+
footprint = simulator_size_on_disk
|
392
341
|
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
end
|
399
|
-
|
400
|
-
is_stable = false
|
401
|
-
waited_for_boot = false
|
402
|
-
waited_for_ipad = false
|
403
|
-
stable_count = 0
|
404
|
-
|
405
|
-
while Time.now < poll_until do
|
406
|
-
latest_dir_sha = simulator_data_directory_sha
|
407
|
-
if is_xcode8
|
408
|
-
latest_log_sha = true
|
342
|
+
if version.major >= 9 && footprint < 18
|
343
|
+
first_launch = true
|
344
|
+
elsif version.major == 8
|
345
|
+
if version.minor >= 3 && footprint < 19
|
346
|
+
first_launch = true
|
409
347
|
else
|
410
|
-
|
348
|
+
first_launch = footprint < 11
|
411
349
|
end
|
350
|
+
else
|
351
|
+
first_launch = false
|
352
|
+
end
|
412
353
|
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
process_name = "com.apple.audio.SystemSoundServer-iOS-Simulator"
|
421
|
-
RunLoop::ProcessWaiter.new(process_name, boot_screen_wait_options).wait_for_any
|
422
|
-
waited_for_boot = true
|
423
|
-
stable_count = 0
|
424
|
-
elsif is_gte_ios9 && is_ipad && !waited_for_ipad
|
425
|
-
RunLoop.log_debug("Waiting additional time for iOS 9 iPad to stabilize")
|
426
|
-
sleep(additional_ipad_delay)
|
427
|
-
waited_for_ipad = true
|
428
|
-
stable_count = 0
|
429
|
-
else
|
430
|
-
break
|
431
|
-
end
|
354
|
+
while !required.empty? && Time.now < poll_until do
|
355
|
+
sleep(0.5)
|
356
|
+
required = required.map do |process_name|
|
357
|
+
if simulator_process_running?(process_name)
|
358
|
+
nil
|
359
|
+
else
|
360
|
+
process_name
|
432
361
|
end
|
433
|
-
end
|
434
|
-
|
435
|
-
current_dir_sha = latest_dir_sha
|
436
|
-
current_log_sha = latest_log_sha
|
437
|
-
sleep(delay)
|
362
|
+
end.compact
|
438
363
|
end
|
439
364
|
|
440
|
-
if
|
365
|
+
if required.empty?
|
441
366
|
elapsed = Time.now - now
|
442
|
-
RunLoop.log_debug("
|
367
|
+
RunLoop.log_debug("All required simulator processes have started after #{elapsed}")
|
368
|
+
if first_launch
|
369
|
+
RunLoop.log_debug("Detected a first launch, waiting a little longer - footprint was #{footprint} MB")
|
370
|
+
sleep(RunLoop::Environment.ci? ? 10 : 5)
|
371
|
+
end
|
372
|
+
RunLoop.log_debug("Waited for #{elapsed} seconds for simulator to stabilize")
|
443
373
|
else
|
444
374
|
RunLoop.log_debug("Timed out after #{timeout} seconds waiting for simulator to stabilize")
|
445
375
|
end
|
@@ -541,9 +471,61 @@ failed with this output:
|
|
541
471
|
simulator_languages
|
542
472
|
end
|
543
473
|
|
474
|
+
# @!visibility private
|
475
|
+
def simulator_running_app_details
|
476
|
+
pids = simulator_running_app_pids
|
477
|
+
running_apps = {}
|
478
|
+
|
479
|
+
pids.each do |pid|
|
480
|
+
cmd = ["ps", "-o", "comm=", "-p", pid.to_s]
|
481
|
+
|
482
|
+
hash = run_shell_command(cmd)
|
483
|
+
out = hash[:out]
|
484
|
+
|
485
|
+
if out.nil? || out == "" || out.strip.nil?
|
486
|
+
nil
|
487
|
+
else
|
488
|
+
name = out.strip.split("/").last
|
489
|
+
|
490
|
+
cmd = ["ps", "-o", "command=", "-p", pid.to_s]
|
491
|
+
hash = run_shell_command(cmd)
|
492
|
+
out = hash[:out]
|
493
|
+
|
494
|
+
if out.nil? || out == "" || out.strip.nil?
|
495
|
+
nil
|
496
|
+
else
|
497
|
+
tokens = out.split("#{name} ")
|
498
|
+
|
499
|
+
# No arguments
|
500
|
+
if tokens.count == 1
|
501
|
+
args = ""
|
502
|
+
else
|
503
|
+
args = tokens.last.strip
|
504
|
+
end
|
505
|
+
|
506
|
+
running_apps[name] = {
|
507
|
+
args: args,
|
508
|
+
command: out.strip
|
509
|
+
}
|
510
|
+
end
|
511
|
+
end
|
512
|
+
end
|
513
|
+
|
514
|
+
running_apps
|
515
|
+
end
|
516
|
+
|
517
|
+
=begin
|
518
|
+
PRIVATE METHODS
|
519
|
+
=end
|
520
|
+
|
544
521
|
private
|
545
522
|
|
546
|
-
attr_reader :pbuddy, :simctl, :xcrun
|
523
|
+
attr_reader :pbuddy, :simctl, :xcrun, :xcode
|
524
|
+
|
525
|
+
# @!visibility private
|
526
|
+
def xcode
|
527
|
+
@xcode ||= RunLoop::Xcode.new
|
528
|
+
end
|
547
529
|
|
548
530
|
# @!visibility private
|
549
531
|
def xcrun
|
@@ -610,6 +592,76 @@ failed with this output:
|
|
610
592
|
udid
|
611
593
|
end
|
612
594
|
|
595
|
+
# @!visibility private
|
596
|
+
def simulator_required_child_processes
|
597
|
+
@simulator_required_child_processes ||= begin
|
598
|
+
required = ["backboardd", "installd", "SimulatorBridge", "SpringBoard"]
|
599
|
+
if xcode.version_gte_8? && version.major > 8
|
600
|
+
required << "medialibraryd"
|
601
|
+
end
|
602
|
+
|
603
|
+
if simulator_is_ipad? && version.major == 9
|
604
|
+
required << "com.apple.audio.SystemSoundServer-iOS-Simulator"
|
605
|
+
end
|
606
|
+
|
607
|
+
required
|
608
|
+
end
|
609
|
+
end
|
610
|
+
|
611
|
+
# @!visibility private
|
612
|
+
def simulator_launchd_sim_pid
|
613
|
+
waiter = RunLoop::ProcessWaiter.new("launchd_sim")
|
614
|
+
waiter.wait_for_any
|
615
|
+
|
616
|
+
return nil if !waiter.running_process?
|
617
|
+
|
618
|
+
pid = nil
|
619
|
+
|
620
|
+
waiter.pids.each do |launchd_sim_pid|
|
621
|
+
cmd = ["ps", "x", "-o", "pid,command", launchd_sim_pid.to_s]
|
622
|
+
hash = run_shell_command(cmd)
|
623
|
+
out = hash[:out]
|
624
|
+
process_line = out.split($-0)[1]
|
625
|
+
if !process_line || process_line == ""
|
626
|
+
false
|
627
|
+
else
|
628
|
+
pid = process_line.split(" ").first.strip
|
629
|
+
if process_line[/#{udid}/] == nil
|
630
|
+
RunLoop.log_debug("Terminating launchd_sim process with pid #{pid}")
|
631
|
+
RunLoop::ProcessTerminator.new(pid, "KILL", "launchd_sim").kill_process
|
632
|
+
pid = nil
|
633
|
+
end
|
634
|
+
end
|
635
|
+
end
|
636
|
+
pid
|
637
|
+
end
|
638
|
+
|
639
|
+
# @!visibility private
|
640
|
+
def process_parent_is_launchd_sim?(pid)
|
641
|
+
launchd_sim_pid = simulator_launchd_sim_pid
|
642
|
+
return false if !launchd_sim_pid
|
643
|
+
|
644
|
+
cmd = ["ps", "x", "-o", "ppid=", "-p", pid.to_s]
|
645
|
+
hash = run_shell_command(cmd)
|
646
|
+
|
647
|
+
out = hash[:out]
|
648
|
+
if out.nil? || out == ""
|
649
|
+
false
|
650
|
+
else
|
651
|
+
ppid = out.strip
|
652
|
+
ppid == launchd_sim_pid.to_s
|
653
|
+
end
|
654
|
+
end
|
655
|
+
|
656
|
+
# @!visibility private
|
657
|
+
def simulator_process_running?(process_name)
|
658
|
+
waiter = RunLoop::ProcessWaiter.new(process_name)
|
659
|
+
waiter.pids.any? do |pid|
|
660
|
+
process_parent_is_launchd_sim?(pid)
|
661
|
+
#process_parent_is_current_xcode?(pid)
|
662
|
+
end
|
663
|
+
end
|
664
|
+
|
613
665
|
# @!visibility private
|
614
666
|
def simulator_data_directory_sha
|
615
667
|
path = File.join(simulator_root_dir, 'data')
|
@@ -688,6 +740,26 @@ https://github.com/calabash/calabash-ios/wiki/Testing-on-Physical-Devices
|
|
688
740
|
end
|
689
741
|
true
|
690
742
|
end
|
743
|
+
|
744
|
+
# @!visibility private
|
745
|
+
def simulator_running_app_pids
|
746
|
+
simulator_running_user_app_pids +
|
747
|
+
simulator_running_system_app_pids
|
748
|
+
end
|
749
|
+
|
750
|
+
# @!visibility private
|
751
|
+
def simulator_running_user_app_pids
|
752
|
+
path = File.join(udid, "data", "Containers", "Bundle")
|
753
|
+
RunLoop::ProcessWaiter.pgrep_f(path)
|
754
|
+
end
|
755
|
+
|
756
|
+
# @!visibility private
|
757
|
+
def simulator_running_system_app_pids
|
758
|
+
base_dir = xcode.developer_dir
|
759
|
+
sim_apps_dir = "Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/Applications"
|
760
|
+
path = File.expand_path(File.join(base_dir, sim_apps_dir))
|
761
|
+
RunLoop::ProcessWaiter.pgrep_f(path)
|
762
|
+
end
|
691
763
|
end
|
692
764
|
end
|
693
765
|
|
Binary file
|
Binary file
|
Binary file
|
@@ -38,12 +38,20 @@ module RunLoop
|
|
38
38
|
|
39
39
|
# Ignored in the XTC.
|
40
40
|
# This key is subject to removal or changes
|
41
|
-
:device_agent_install_timeout => RunLoop::Environment.ci? ?
|
41
|
+
:device_agent_install_timeout => RunLoop::Environment.ci? ? 240 : 120,
|
42
42
|
# This value must always be false on the XTC.
|
43
43
|
# This is should only be used by gem maintainers or very advanced users.
|
44
|
-
:shutdown_device_agent_before_launch => false
|
44
|
+
:shutdown_device_agent_before_launch => false,
|
45
|
+
|
46
|
+
# This value was derived empirically by typing hundreds of strings
|
47
|
+
# using XCUIElement#typeText. It corresponds to the DeviceAgent
|
48
|
+
# constant CBX_DEFAULT_SEND_STRING_FREQUENCY which is 60. _Decrease_
|
49
|
+
# this value if you are timing out typing strings.
|
50
|
+
:characters_per_second => 12
|
45
51
|
}
|
46
52
|
|
53
|
+
AUT_LAUNCHED_BY_RUN_LOOP_ARG = "LAUNCHED_BY_RUN_LOOP"
|
54
|
+
|
47
55
|
# @!visibility private
|
48
56
|
#
|
49
57
|
# These defaults may change at any time.
|
@@ -67,7 +75,6 @@ module RunLoop
|
|
67
75
|
|
68
76
|
# @!visibility private
|
69
77
|
def self.run(options={})
|
70
|
-
# logger = options[:logger]
|
71
78
|
simctl = options[:sim_control] || options[:simctl] || RunLoop::Simctl.new
|
72
79
|
xcode = options[:xcode] || RunLoop::Xcode.new
|
73
80
|
instruments = options[:instruments] || RunLoop::Instruments.new
|
@@ -88,10 +95,19 @@ module RunLoop
|
|
88
95
|
default_options = {
|
89
96
|
:xcode => xcode
|
90
97
|
}
|
98
|
+
|
91
99
|
merged_options = default_options.merge(options)
|
92
100
|
|
93
101
|
if device.simulator? && app
|
102
|
+
RunLoop::Core.expect_simulator_compatible_arch(device, app)
|
103
|
+
|
104
|
+
if merged_options[:relaunch_simulator]
|
105
|
+
RunLoop.log_debug("Detected :relaunch_simulator option; will force simulator to restart")
|
106
|
+
RunLoop::CoreSimulator.quit_simulator
|
107
|
+
end
|
108
|
+
|
94
109
|
core_sim = RunLoop::CoreSimulator.new(device, app, merged_options)
|
110
|
+
|
95
111
|
if reset_options
|
96
112
|
core_sim.reset_app_sandbox
|
97
113
|
end
|
@@ -100,7 +116,7 @@ module RunLoop
|
|
100
116
|
core_sim.install
|
101
117
|
end
|
102
118
|
|
103
|
-
cbx_launcher = Client.detect_cbx_launcher(
|
119
|
+
cbx_launcher = Client.detect_cbx_launcher(merged_options, device)
|
104
120
|
|
105
121
|
code_sign_identity = options[:code_sign_identity]
|
106
122
|
if !code_sign_identity
|
@@ -114,6 +130,10 @@ module RunLoop
|
|
114
130
|
aut_args = options.fetch(:args, [])
|
115
131
|
aut_env = options.fetch(:env, {})
|
116
132
|
|
133
|
+
if !aut_args.include?(AUT_LAUNCHED_BY_RUN_LOOP_ARG)
|
134
|
+
aut_args << AUT_LAUNCHED_BY_RUN_LOOP_ARG
|
135
|
+
end
|
136
|
+
|
117
137
|
launcher_options = {
|
118
138
|
code_sign_identity: code_sign_identity,
|
119
139
|
device_agent_install_timeout: install_timeout,
|
@@ -282,6 +302,9 @@ INSTANCE METHODS
|
|
282
302
|
# @!visibility private
|
283
303
|
#
|
284
304
|
# Experimental!
|
305
|
+
#
|
306
|
+
# This will launch the other app using the same arguments and environment
|
307
|
+
# as the AUT.
|
285
308
|
def launch_other_app(bundle_id)
|
286
309
|
launch_aut(bundle_id)
|
287
310
|
end
|
@@ -327,7 +350,9 @@ INSTANCE METHODS
|
|
327
350
|
|
328
351
|
# @!visibility private
|
329
352
|
def clear_text
|
330
|
-
|
353
|
+
# Tries to touch the keyboard delete key, but falls back on typing the
|
354
|
+
# backspace character.
|
355
|
+
options = enter_text_http_options("\b")
|
331
356
|
parameters = {
|
332
357
|
:gesture => "clear_text"
|
333
358
|
}
|
@@ -342,7 +367,7 @@ INSTANCE METHODS
|
|
342
367
|
if !keyboard_visible?
|
343
368
|
raise RuntimeError, "Keyboard must be visible"
|
344
369
|
end
|
345
|
-
options = enter_text_http_options
|
370
|
+
options = enter_text_http_options(string.to_s)
|
346
371
|
parameters = {
|
347
372
|
:gesture => "enter_text",
|
348
373
|
:options => {
|
@@ -362,7 +387,7 @@ INSTANCE METHODS
|
|
362
387
|
# 1. Removes duplicate check.
|
363
388
|
# 2. It turns out DeviceAgent query can be very slow.
|
364
389
|
def enter_text_without_keyboard_check(string)
|
365
|
-
options = enter_text_http_options
|
390
|
+
options = enter_text_http_options(string.to_s)
|
366
391
|
parameters = {
|
367
392
|
:gesture => "enter_text",
|
368
393
|
:options => {
|
@@ -752,6 +777,20 @@ Timed out after #{timeout} seconds waiting for the keyboard to appear.
|
|
752
777
|
end
|
753
778
|
end
|
754
779
|
|
780
|
+
# @!visibility private
|
781
|
+
def wait_for_no_keyboard(timeout=WAIT_DEFAULTS[:timeout])
|
782
|
+
options = WAIT_DEFAULTS.dup
|
783
|
+
options[:timeout] = timeout
|
784
|
+
message = %Q[
|
785
|
+
|
786
|
+
Timed out after #{timeout} seconds waiting for the keyboard to disappear.
|
787
|
+
|
788
|
+
]
|
789
|
+
wait_for(message, options) do
|
790
|
+
!keyboard_visible?
|
791
|
+
end
|
792
|
+
end
|
793
|
+
|
755
794
|
# @!visibility private
|
756
795
|
def wait_for_alert(timeout=WAIT_DEFAULTS[:timeout])
|
757
796
|
options = WAIT_DEFAULTS.dup
|
@@ -784,23 +823,52 @@ Timed out after #{timeout} seconds waiting for an alert to disappear.
|
|
784
823
|
# @!visibility private
|
785
824
|
def wait_for_text_in_view(text, uiquery, options={})
|
786
825
|
merged_options = WAIT_DEFAULTS.merge(options)
|
787
|
-
result = wait_for_view(uiquery, merged_options)
|
788
|
-
|
789
|
-
# This is not quite right. It is possible to get a false positive.
|
790
|
-
# If result does not have "value" or "label" and the text is nil
|
791
|
-
candidates = [result["value"],
|
792
|
-
result["label"]]
|
793
|
-
match = candidates.any? do |elm|
|
794
|
-
elm == text
|
795
|
-
end
|
796
|
-
if !match
|
797
|
-
fail(%Q[
|
798
826
|
|
799
|
-
|
827
|
+
begin
|
828
|
+
wait_for("TMP", merged_options) do
|
829
|
+
view = query(uiquery).first
|
830
|
+
|
831
|
+
if view
|
832
|
+
# Guard against this edge case:
|
833
|
+
#
|
834
|
+
# Text is "" and value or label keys do not exist in view which
|
835
|
+
# implies that value or label was the empty string (see the
|
836
|
+
# DeviceAgent JSONUtils and Facebook macros).
|
837
|
+
if text == "" || text == nil
|
838
|
+
view["value"] == nil && view["label"] == nil
|
839
|
+
else
|
840
|
+
[view["value"], view["label"]].any? { |elm| elm == text }
|
841
|
+
end
|
842
|
+
else
|
843
|
+
false
|
844
|
+
end
|
845
|
+
end
|
846
|
+
rescue merged_options[:exception_class] => e
|
847
|
+
view = query(uiquery)
|
848
|
+
if !view
|
849
|
+
message = %Q[
|
850
|
+
Timed out wait after #{merged_options[:timeout]} seconds waiting for a view to match:
|
800
851
|
|
801
|
-
#{
|
852
|
+
#{uiquery}
|
802
853
|
|
803
|
-
]
|
854
|
+
]
|
855
|
+
else
|
856
|
+
message = %Q[
|
857
|
+
Timed out after #{merged_options[:timeout]} seconds waiting for a view matching:
|
858
|
+
|
859
|
+
'#{uiquery}'
|
860
|
+
|
861
|
+
to have 'value' or 'label' matching text:
|
862
|
+
|
863
|
+
'#{text}'
|
864
|
+
|
865
|
+
Found:
|
866
|
+
|
867
|
+
#{JSON.pretty_generate(view)}
|
868
|
+
|
869
|
+
]
|
870
|
+
end
|
871
|
+
fail(merged_options[:exception_class], message)
|
804
872
|
end
|
805
873
|
end
|
806
874
|
|
@@ -1069,8 +1137,11 @@ PRIVATE
|
|
1069
1137
|
# @!visibility private
|
1070
1138
|
#
|
1071
1139
|
# A patch while we are trying to figure out what is wrong with text entry.
|
1072
|
-
def enter_text_http_options
|
1073
|
-
|
1140
|
+
def enter_text_http_options(string)
|
1141
|
+
characters = string.length + 1
|
1142
|
+
characters_per_second = DEFAULTS[:characters_per_second]
|
1143
|
+
to_type_timeout = [characters/characters_per_second, 2.0].max
|
1144
|
+
timeout = (DEFAULTS[:http_timeout] * 3) + to_type_timeout
|
1074
1145
|
{
|
1075
1146
|
:timeout => timeout,
|
1076
1147
|
:interval => 0.1,
|
@@ -1178,21 +1249,26 @@ PRIVATE
|
|
1178
1249
|
hash
|
1179
1250
|
end
|
1180
1251
|
|
1181
|
-
#
|
1182
|
-
# that iOSDeviceManager will be able to handle this for us.
|
1252
|
+
# @!visibility private
|
1183
1253
|
def cbx_runner_stale?
|
1184
|
-
false
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1254
|
+
return false if RunLoop::Environment.xtc?
|
1255
|
+
return false if cbx_launcher.name == :xcodebuild
|
1256
|
+
return false if !running?
|
1257
|
+
|
1258
|
+
version_info = server_version
|
1259
|
+
running_version_timestamp = version_info[:bundle_version].to_i
|
1260
|
+
|
1261
|
+
app = RunLoop::App.new(cbx_launcher.runner.runner)
|
1262
|
+
plist_buddy = RunLoop::PlistBuddy.new
|
1263
|
+
version_timestamp = plist_buddy.plist_read("CFBundleVersion", app.info_plist_path).to_i
|
1190
1264
|
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1265
|
+
if running_version_timestamp == version_timestamp
|
1266
|
+
RunLoop.log_debug("The running DeviceAgent version is the same as the version on disk")
|
1267
|
+
false
|
1268
|
+
else
|
1269
|
+
RunLoop.log_debug("The running DeviceAgent version is not the same as the version on disk")
|
1270
|
+
true
|
1271
|
+
end
|
1196
1272
|
end
|
1197
1273
|
|
1198
1274
|
# @!visibility private
|
@@ -1289,7 +1365,7 @@ Please install it.
|
|
1289
1365
|
client = http_client(http_options)
|
1290
1366
|
request = request("session",
|
1291
1367
|
{
|
1292
|
-
:
|
1368
|
+
:bundle_id => bundle_id,
|
1293
1369
|
:launchArgs => aut_args,
|
1294
1370
|
:environment => aut_env
|
1295
1371
|
})
|