uiauto 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +34 -8
- data/helpers/choose_sim_device +68 -0
- data/lib/uiauto/cli.rb +29 -6
- data/lib/uiauto/formatters.rb +6 -0
- data/lib/uiauto/formatters/README.md +30 -0
- data/lib/uiauto/formatters/base_formatter.rb +11 -0
- data/lib/uiauto/formatters/color_indent_formatter.rb +123 -0
- data/lib/uiauto/formatters/instruments_formatter.rb +11 -0
- data/lib/uiauto/instruments.rb +49 -22
- data/lib/uiauto/listeners.rb +5 -0
- data/lib/uiauto/listeners/README.md +15 -0
- data/lib/uiauto/listeners/base_listener.rb +93 -0
- data/lib/uiauto/listeners/exit_status_listener.rb +25 -0
- data/lib/uiauto/reporter.rb +83 -0
- data/lib/uiauto/runner.rb +35 -15
- data/lib/uiauto/simulator.rb +16 -1
- data/lib/uiauto/version.rb +1 -1
- data/uiauto.gemspec +2 -0
- metadata +41 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3afb5260e2a269072122eb099792ea8a95b27547
|
4
|
+
data.tar.gz: c120b7d250ce0524788a53404df05eac9321842e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1184ac99f15aae6feadb3332fb1122e451190c29f36d165228e69e82edc6b6ae2925bdc6de5529311d9f12b979eee5350b6efa8221ef88404783adfad27cf4a6
|
7
|
+
data.tar.gz: 37a0d0f6b8fb720379560cca0649fe4555f6547da3f7739e4834ec00d834b9d3800efb1badd2760d707519b8e6c5d81c77c4303c3fd08926a7bbe517bb3f43cc
|
data/README.md
CHANGED
@@ -4,6 +4,8 @@ UIAuto is a command line tool for running UI Automation scripts. It improves App
|
|
4
4
|
|
5
5
|
UIAuto also facilitates the setup of simulator data for running scripts in a repeatable and known state.
|
6
6
|
|
7
|
+
![screencast](http://enriquez.me/uiauto/uiauto.gif)
|
8
|
+
|
7
9
|
## Prerequisites
|
8
10
|
|
9
11
|
* Xcode command line tools
|
@@ -14,7 +16,7 @@ UIAuto also facilitates the setup of simulator data for running scripts in a rep
|
|
14
16
|
|
15
17
|
## Usage
|
16
18
|
|
17
|
-
First, you need to build your app
|
19
|
+
First, you need to build your app. By default, `uiauto` will look for the most recently built app bundle in derived data based on your current working directory. UIAuto also provides commands and can read speical comment headers to setup simulator data. More details below.
|
18
20
|
|
19
21
|
### Build your project
|
20
22
|
|
@@ -48,6 +50,11 @@ In the same directory as your project's .xcworkspace or .xcodeproj run the follo
|
|
48
50
|
|
49
51
|
This will run `path_to_your_script.js` using the app bundle located in derivated data that you just built. The results and trace file are placed in `./uiauto/results` and `./uiauto/results/trace`.
|
50
52
|
|
53
|
+
By placing your scripts in `./uiauto/scripts/`, then you can execute them by running the following command.
|
54
|
+
|
55
|
+
# This is the same as `uiauto exec uiauto/scripts/`
|
56
|
+
$ uiauto exec
|
57
|
+
|
51
58
|
#### Advanced options
|
52
59
|
|
53
60
|
Running `uiauto help exec` prints the following message.
|
@@ -56,18 +63,29 @@ Running `uiauto help exec` prints the following message.
|
|
56
63
|
uiauto exec [FILE_OR_DIRECTORY]
|
57
64
|
|
58
65
|
Options:
|
59
|
-
[--results=RESULTS]
|
60
|
-
|
61
|
-
[--trace=TRACE]
|
62
|
-
|
63
|
-
[--app=APP]
|
64
|
-
|
65
|
-
[--
|
66
|
+
[--results=RESULTS] # Location where results should be saved. A directory named "Run ##" is created in here.
|
67
|
+
# Default: ./uiauto/results
|
68
|
+
[--trace=TRACE] # Location of trace file. Created if it doesn't exist.
|
69
|
+
# Default: ./uiauto/results/trace
|
70
|
+
[--app=APP] # Location of your application bundle. Defaults to your project's most recent build located in the standard location.
|
71
|
+
[--device=DEVICE] # Run scripts on a connected device. Specify a UDID to target a specific device.
|
72
|
+
[--simulator=SIMULATOR] # Run the simulator for a specific device.
|
73
|
+
# Possible values: iPad, iPad (Retina), iPhone, iPhone (Retina 3.5-inch), iPhone (Retina 4-inch)
|
74
|
+
[--format=FORMAT] # Formatter to use for output. Combine with --require to include a custom formatter. Built-in Formatters:
|
75
|
+
# ColorIndentFormatter: Adds readability to instruments output by filtering noise and adding color and indents.
|
76
|
+
# InstrumentsFormatter: Unmodified instruments output.
|
77
|
+
# Default: ColorIndentFormatter
|
78
|
+
[--listeners=LISTENERS] # Space separated list of class names used to listen to instruments output events. Combine with --require to include custom listeners.
|
79
|
+
[--require=REQUIRE] # Path to a ruby file. Used to require custom formatters or listeners.
|
80
|
+
|
81
|
+
##### `--app` option
|
66
82
|
|
67
83
|
If you build your app outside of derived data, then you can specify the `--app` flag to tell uiauto where to find the `*.app`. You can also override the default locations for the trace file and results. For example, if your build your app in a build directory you can run the following
|
68
84
|
|
69
85
|
uiauto exec uiauto/scripts/script_to_run.js --app=build/MyApp.app
|
70
86
|
|
87
|
+
##### `--device` option
|
88
|
+
|
71
89
|
Pass the `--device` flag to run on the device.
|
72
90
|
|
73
91
|
# Run on a connected device
|
@@ -76,6 +94,14 @@ Pass the `--device` flag to run on the device.
|
|
76
94
|
# Run on a connected device with a specific udid
|
77
95
|
$ uiauto exec uiauto/scripts/script_to_run.js --device=UDID
|
78
96
|
|
97
|
+
##### Custom formatters and listeners
|
98
|
+
|
99
|
+
UIAuto supports custom formats and custom listeners. They can be made available with the `--require` option. The difference between a formatter and listener is that a formatter is a specific kind of listener that writes to `STDOUT`. There can only be one formatter active at a time. There may be more than one listener active at a time, and a listener must not write to `STDOUT`.
|
100
|
+
|
101
|
+
See [lib/uiauto/formatters/README.md](https://github.com/enriquez/uiauto/tree/master/lib/uiauto/formatters/) for details on how to implement a custom formatter.
|
102
|
+
|
103
|
+
See [lib/uiauto/listeners/README.md](https://github.com/enriquez/uiauto/tree/master/lib/uiauto/listeners/) for details on how to implement a custom listener.
|
104
|
+
|
79
105
|
### Simulator data
|
80
106
|
|
81
107
|
UIAuto's `simulator` subcommand allows you to setup the simulator's applications, settings, and data. This is done by taking a "snapshot" of the simulator's current data by saving the `~/Library/Application Support/iPhone Simulator/(SDK VERSION)/` directory somewhere, then loading it back in when needed.
|
@@ -0,0 +1,68 @@
|
|
1
|
+
#!/usr/bin/env osascript
|
2
|
+
|
3
|
+
(*
|
4
|
+
Copyright (c) 2012 Jonathan Penn (http://cocoamanifest.net/)
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
8
|
+
in the Software without restriction, including without limitation the rights
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in
|
14
|
+
all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
+
THE SOFTWARE.
|
23
|
+
|
24
|
+
Chooses a device type from the iPhone Simulator using menu
|
25
|
+
selection events.
|
26
|
+
|
27
|
+
To use, make sure this file is executable, then run from the terminal:
|
28
|
+
|
29
|
+
bin/choose_sim_device "iPad (Retina)"
|
30
|
+
|
31
|
+
Originally, I tried to do this by editing the Preference file for the
|
32
|
+
simulator, and it worked under Xcode 4.3, but now it ignores those changes
|
33
|
+
often enough that I chose to use this menu-selection route.
|
34
|
+
|
35
|
+
*)
|
36
|
+
|
37
|
+
on run argv
|
38
|
+
set simType to item 1 of argv
|
39
|
+
|
40
|
+
activate application "iPhone Simulator"
|
41
|
+
tell application "System Events"
|
42
|
+
tell process "iOS Simulator"
|
43
|
+
tell menu bar 1
|
44
|
+
-- Hardware menu bar item
|
45
|
+
tell menu bar item 5
|
46
|
+
-- Hardware menu
|
47
|
+
tell menu 1
|
48
|
+
-- Device menu item
|
49
|
+
tell menu item 1
|
50
|
+
-- Device sub menu
|
51
|
+
tell menu 1
|
52
|
+
click menu item simType
|
53
|
+
end tell
|
54
|
+
end tell
|
55
|
+
end tell
|
56
|
+
end tell
|
57
|
+
end tell
|
58
|
+
end tell
|
59
|
+
end tell
|
60
|
+
|
61
|
+
-- Need to show the simulator again after changing device,
|
62
|
+
-- or else the simulator be hidden when launched by instruments
|
63
|
+
-- for some odd reason.
|
64
|
+
tell application "System Events"
|
65
|
+
set visible of process "iOS Simulator" to true
|
66
|
+
end tell
|
67
|
+
|
68
|
+
end run
|
data/lib/uiauto/cli.rb
CHANGED
@@ -28,8 +28,11 @@ module UIAuto
|
|
28
28
|
end
|
29
29
|
|
30
30
|
desc "open", "Opens the simulator"
|
31
|
+
method_option :simulator,
|
32
|
+
:enum => Simulator::DEVICES,
|
33
|
+
:desc => %q{Run the simulator for a specific device.}
|
31
34
|
def open
|
32
|
-
Simulator.open
|
35
|
+
Simulator.open(options[:simulator])
|
33
36
|
end
|
34
37
|
|
35
38
|
desc "close", "Closes the simulator"
|
@@ -40,15 +43,35 @@ module UIAuto
|
|
40
43
|
|
41
44
|
class CLI < Thor
|
42
45
|
desc "exec FILE_OR_DIRECTORY", "Runs the given script or directory of scripts through UI Automation"
|
43
|
-
method_option :results,
|
44
|
-
|
45
|
-
|
46
|
-
method_option :
|
46
|
+
method_option :results,
|
47
|
+
:default => File.expand_path("./uiauto/results"),
|
48
|
+
:desc => %q{Location where results should be saved. A directory named "Run ##" is created in here.}
|
49
|
+
method_option :trace,
|
50
|
+
:default => File.expand_path("./uiauto/results/trace"),
|
51
|
+
:desc => %q{Location of trace file. Created if it doesn't exist.}
|
52
|
+
method_option :app,
|
53
|
+
:desc => %q{Location of your application bundle. Defaults to your project's most recent build located in the standard derived data location.}
|
54
|
+
method_option :device,
|
55
|
+
:desc => %q{Run scripts on a connected device. Specify a UDID to target a specific device.}
|
56
|
+
method_option :simulator,
|
57
|
+
:enum => Simulator::DEVICES,
|
58
|
+
:desc => %q{Run the simulator for a specific device.}
|
59
|
+
method_option :format,
|
60
|
+
:default => "ColorIndentFormatter",
|
61
|
+
:desc => %q{Formatter to use for output. Combine with --require to include a custom formatter. Built-in Formatters:
|
62
|
+
# ColorIndentFormatter: Adds readability to instruments output by filtering noise and adding color and indents.
|
63
|
+
# InstrumentsFormatter: Unmodified instruments output.}
|
64
|
+
method_option :listeners,
|
65
|
+
:type => :array,
|
66
|
+
:banner => "LISTENERS",
|
67
|
+
:desc => %q{Space separated list of class names used to listen to instruments output events. Combine with --require to include custom listeners.}
|
68
|
+
method_option :require,
|
69
|
+
:desc => %q{Path to a ruby file. Used to require custom formatters or listeners.}
|
47
70
|
def exec(file_or_dir = "./uiauto/scripts/")
|
48
71
|
Runner.run(file_or_dir, options)
|
49
72
|
end
|
50
73
|
|
51
|
-
desc "simulator SUBCOMMAND ...ARGS", "
|
74
|
+
desc "simulator SUBCOMMAND ...ARGS", "Manage simulator data"
|
52
75
|
subcommand "simulator", SimulatorCLI
|
53
76
|
end
|
54
77
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# UIAuto Formatters
|
2
|
+
|
3
|
+
A formatter is a special type of listener that writes to `STDOUT`. To create a custom formatter, inherit from `UIAuto::Formatters::BaseFormatter` and place it in the `UIAuto::Formatters` namespace. Then override the methods important to your formatter.
|
4
|
+
|
5
|
+
Below is an example of a basic progress formatter.
|
6
|
+
|
7
|
+
# progress_formatter.rb
|
8
|
+
require 'uiauto/formatters/base_formatter'
|
9
|
+
|
10
|
+
module UIAuto
|
11
|
+
module Formatters
|
12
|
+
class ProgressFormatter < BaseFormatter
|
13
|
+
def log_debug(message)
|
14
|
+
output.print "."
|
15
|
+
end
|
16
|
+
|
17
|
+
def log_fail(message)
|
18
|
+
output.print "F"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
This formatter can be used by requiring the script and setting the format.
|
25
|
+
|
26
|
+
$ uiauto exec uiauto/scripts/script_to_run.js --require=./progress_formatter.rb --format=ProgressFormatter
|
27
|
+
|
28
|
+
See [lib/uiauto/listeners/base_listener.rb](https://github.com/enriquez/uiauto/tree/master/lib/uiauto/listeners/base_listener.rb) for the available methods and their description.
|
29
|
+
|
30
|
+
See [lib/uiauto/formatters/](https://github.com/enriquez/uiauto/tree/master/lib/uiauto/formatters/) for examples of built in formatters.
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'uiauto/formatters/base_formatter'
|
2
|
+
require 'rainbow'
|
3
|
+
|
4
|
+
module UIAuto
|
5
|
+
module Formatters
|
6
|
+
class ColorIndentFormatter < BaseFormatter
|
7
|
+
def initialize
|
8
|
+
@passes = []
|
9
|
+
@failures = []
|
10
|
+
@current_script = ''
|
11
|
+
end
|
12
|
+
|
13
|
+
def script_start(script)
|
14
|
+
output.puts
|
15
|
+
output.puts "Script: #{script}"
|
16
|
+
@current_script = script
|
17
|
+
end
|
18
|
+
|
19
|
+
def load_simulator_data(path)
|
20
|
+
output.puts
|
21
|
+
output.puts " Simulator Data: #{path}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def log_start(message)
|
25
|
+
output.puts
|
26
|
+
output.puts " Test: \"#{message}\""
|
27
|
+
end
|
28
|
+
|
29
|
+
def log_pass(message)
|
30
|
+
output.puts " Test: \"#{message}\" Passed".foreground(:green)
|
31
|
+
@passes << message
|
32
|
+
end
|
33
|
+
|
34
|
+
def log_fail(message)
|
35
|
+
output.puts " Test: \"#{message}\" Failed".foreground(:red)
|
36
|
+
@failures << "#{@current_script} \"#{message}\""
|
37
|
+
end
|
38
|
+
|
39
|
+
def log_issue(message)
|
40
|
+
output.puts " Test: \"#{message}\" Issue".foreground(:yellow)
|
41
|
+
end
|
42
|
+
|
43
|
+
def log_debug(message)
|
44
|
+
if output.tty?
|
45
|
+
colored_message = message.foreground(:cyan)
|
46
|
+
colored_message = colored_message.gsub(/"((?:[^"\\]|\\.)*)"/) do
|
47
|
+
# hack to ensure ansi start/end codes for cyan are matched between bright cyan
|
48
|
+
"\e[0m#{"\"#{$1}\"".bright.foreground(:cyan)}\e[36m"
|
49
|
+
end
|
50
|
+
|
51
|
+
message = colored_message
|
52
|
+
end
|
53
|
+
output.puts " #{message}"
|
54
|
+
end
|
55
|
+
|
56
|
+
def log_error(message)
|
57
|
+
output.puts " Error: #{message}".foreground(:red)
|
58
|
+
end
|
59
|
+
|
60
|
+
def log_default(message)
|
61
|
+
output.puts message
|
62
|
+
end
|
63
|
+
|
64
|
+
def log_warning(message)
|
65
|
+
output.puts " Warning: #{message}".foreground(:yellow)
|
66
|
+
end
|
67
|
+
|
68
|
+
def log_none(message)
|
69
|
+
output.puts " #{message}".foreground(:red)
|
70
|
+
@failures << @current_script unless @failures.include?(@current_script)
|
71
|
+
end
|
72
|
+
|
73
|
+
def log_stopped(message)
|
74
|
+
output.puts " #{message}".foreground(:red)
|
75
|
+
@failures << @current_script unless @failures.include?(@current_script)
|
76
|
+
end
|
77
|
+
|
78
|
+
def element_tree_start
|
79
|
+
output.puts " Element Tree:".color("333333")
|
80
|
+
end
|
81
|
+
|
82
|
+
def element_tree_line(line)
|
83
|
+
output.puts " #{line}".color("333333")
|
84
|
+
end
|
85
|
+
|
86
|
+
def run_finish
|
87
|
+
if @failures.count > 0
|
88
|
+
output.puts
|
89
|
+
output.puts "Failing Tests:".foreground(:red)
|
90
|
+
@failures.each do |failure|
|
91
|
+
output.puts failure.foreground(:red)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
output.puts
|
96
|
+
output.puts "#{@passes.count + @failures.count} tests #{summary}"
|
97
|
+
end
|
98
|
+
|
99
|
+
protected
|
100
|
+
|
101
|
+
def summary
|
102
|
+
failures = ''
|
103
|
+
passes = ''
|
104
|
+
|
105
|
+
if @failures.count > 0
|
106
|
+
failures = "#{@failures.count} failed".foreground(:red)
|
107
|
+
end
|
108
|
+
|
109
|
+
if @passes.count > 0
|
110
|
+
passes = "#{@passes.count} passed".foreground(:green)
|
111
|
+
end
|
112
|
+
|
113
|
+
if failures.length > 0 && passes.length > 0
|
114
|
+
"(#{failures}, #{passes})"
|
115
|
+
elsif failures.length > 0
|
116
|
+
"(#{failures})"
|
117
|
+
elsif passes.length > 0
|
118
|
+
"(#{passes})"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
data/lib/uiauto/instruments.rb
CHANGED
@@ -1,17 +1,21 @@
|
|
1
|
-
require '
|
1
|
+
require 'childprocess'
|
2
2
|
require 'fileutils'
|
3
3
|
require 'cfpropertylist'
|
4
|
+
require 'pty'
|
5
|
+
require 'uiauto/simulator'
|
4
6
|
|
5
7
|
module UIAuto
|
6
8
|
class Instruments
|
7
|
-
attr_accessor :trace, :app, :results, :script, :device
|
9
|
+
attr_accessor :trace, :app, :results, :script, :device, :simulator
|
8
10
|
|
9
|
-
def initialize(script, opts = {})
|
10
|
-
@
|
11
|
-
@
|
12
|
-
@
|
13
|
-
@
|
14
|
-
@
|
11
|
+
def initialize(script, reporter, opts = {})
|
12
|
+
@reporter = reporter
|
13
|
+
@script = script
|
14
|
+
@trace = opts[:trace]
|
15
|
+
@results = opts[:results]
|
16
|
+
@device = opts[:device]
|
17
|
+
@simulator = opts[:simulator]
|
18
|
+
@app = opts[:app] || default_application
|
15
19
|
|
16
20
|
FileUtils.mkdir_p(@results) unless File.exists?(@results)
|
17
21
|
end
|
@@ -29,27 +33,31 @@ module UIAuto
|
|
29
33
|
end
|
30
34
|
|
31
35
|
def execute
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
+
launch_simulator
|
37
|
+
select_device_family
|
38
|
+
|
39
|
+
instruments = ChildProcess.build(*command.split(" "))
|
40
|
+
master, slave = if PTY.respond_to?(:open)
|
41
|
+
PTY.open
|
42
|
+
else
|
43
|
+
[File.new("/dev/ptyuf", "w"), File.open("/dev/ttyuf", "r")]
|
44
|
+
end
|
45
|
+
instruments.io.stdout = master
|
46
|
+
instruments.io.stderr = master
|
47
|
+
instruments.duplex = true
|
48
|
+
instruments.start
|
49
|
+
master.close
|
36
50
|
|
37
51
|
begin
|
38
52
|
loop do
|
39
|
-
buffer =
|
40
|
-
|
41
|
-
lines.each do |line|
|
42
|
-
puts line
|
43
|
-
exit_status = 1 if line =~ /Fail:/ && exit_status != 2
|
44
|
-
exit_status = 2 if line =~ /Instruments Usage Error|Instruments Trace Error|^\d+-\d+-\d+ \d+:\d+:\d+ [-+]\d+ (Error:|None: Script threw an uncaught JavaScript error)/
|
45
|
-
end
|
53
|
+
buffer = slave.readpartial(8192)
|
54
|
+
@reporter.parse_instruments_output(buffer)
|
46
55
|
end
|
47
56
|
rescue EOFError
|
57
|
+
@reporter.script_finish(@script)
|
48
58
|
ensure
|
49
|
-
|
59
|
+
slave.close
|
50
60
|
end
|
51
|
-
|
52
|
-
exit_status
|
53
61
|
end
|
54
62
|
|
55
63
|
protected
|
@@ -100,5 +108,24 @@ module UIAuto
|
|
100
108
|
end
|
101
109
|
end
|
102
110
|
|
111
|
+
def launch_simulator
|
112
|
+
Simulator.open(@simulator)
|
113
|
+
end
|
114
|
+
|
115
|
+
def select_device_family
|
116
|
+
if @simulator && !@simulator.empty?
|
117
|
+
info_plist = CFPropertyList::List.new(:file => File.join(@app, "Info.plist"))
|
118
|
+
data = CFPropertyList.native_types(info_plist.value)
|
119
|
+
if @simulator.start_with?("iPhone")
|
120
|
+
data["UIDeviceFamily"] = [1]
|
121
|
+
elsif @simulator.start_with?("iPad")
|
122
|
+
data["UIDeviceFamily"] = [2]
|
123
|
+
end
|
124
|
+
|
125
|
+
info_plist.value = CFPropertyList.guess(data)
|
126
|
+
info_plist.save
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
103
130
|
end
|
104
131
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# UIAuto Listeners
|
2
|
+
|
3
|
+
Listeners receive events from instruments. Listeners may be used for anything other than writing to `STDOUT`. Use a formatter if you plan on writing to `STDOUT`. To create a custom listener, inherit from `UIAuto::Formatters::BaseListener` and place it in the `UIAuto::Listeners` namespace. Then override the methods important to your listener.
|
4
|
+
|
5
|
+
A custom listener can be used by requiring the script and setting the listener.
|
6
|
+
|
7
|
+
$ uiauto exec uiauto/scripts/script_to_run.js --require=./custom_listener.rb --listeners=CustomListener
|
8
|
+
|
9
|
+
More than one listener may be used, but you can only require one file. That file must implement multiple listeners or require other files.
|
10
|
+
|
11
|
+
$ uiauto exec uiauto/scripts/script_to_run.js --require=./listeners.rb --listeners=CustomListener1 CustomListener2
|
12
|
+
|
13
|
+
See [lib/uiauto/listeners/base_listener.rb](https://github.com/enriquez/uiauto/tree/master/lib/uiauto/listeners/base_listener.rb) for the available methods and their description.
|
14
|
+
|
15
|
+
See [lib/uiauto/listeners/](https://github.com/enriquez/uiauto/tree/master/lib/uiauto/listeners/) for examples of built in listeners.
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module UIAuto
|
2
|
+
module Listeners
|
3
|
+
class BaseListener
|
4
|
+
# Before a run is started. A run contains one or more scripts.
|
5
|
+
def run_start
|
6
|
+
end
|
7
|
+
|
8
|
+
# Before a script is started.
|
9
|
+
def script_start(script)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Called if a script contains a comment header to load simulator data.
|
13
|
+
def load_simulator_data(path)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Message printed by UI Automation's logStart.
|
17
|
+
def log_start(message)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Message printed by UI Automation's logPass.
|
21
|
+
def log_pass(message)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Message printed by UI Automation's logFail.
|
25
|
+
def log_fail(message)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Message printed by UI Automation's logIssue.
|
29
|
+
def log_issue(message)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Message printed by UI Automation's logDebug. Also prints actions such as tap, typeString, etc...
|
33
|
+
def log_debug(message)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Message printed by UI Automation's logError.
|
37
|
+
def log_error(message)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Message printed by UI Automation's logMessage.
|
41
|
+
def log_default(message)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Message printed by UI Automation's logWarning.
|
45
|
+
def log_warning(message)
|
46
|
+
end
|
47
|
+
|
48
|
+
# An uncategorized log type. Typically uncaught javascript errors.
|
49
|
+
def log_none(message)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Typically reports a script was stopped by user, but is caused by a failed import
|
53
|
+
def log_stopped(message)
|
54
|
+
end
|
55
|
+
|
56
|
+
# UI Automation's logElementTree was called. element_tree contains the entire tree.
|
57
|
+
def element_tree(element_tree)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Before an element tree starts.
|
61
|
+
def element_tree_start
|
62
|
+
end
|
63
|
+
|
64
|
+
# A line from an element tree.
|
65
|
+
def element_tree_line(line)
|
66
|
+
end
|
67
|
+
|
68
|
+
# After an element tree is finished.
|
69
|
+
def element_tree_finish
|
70
|
+
end
|
71
|
+
|
72
|
+
# After a script is finished. Duration and trace location as reported by instruments.
|
73
|
+
def script_summary(duration, trace_location)
|
74
|
+
end
|
75
|
+
|
76
|
+
# After a script is finished.
|
77
|
+
def script_finish(script)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Misc lines from instruments that are not called in above methods.
|
81
|
+
def unknown(line)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Raw instruments output.
|
85
|
+
def instruments_line(line)
|
86
|
+
end
|
87
|
+
|
88
|
+
# After a run finished.
|
89
|
+
def run_finish
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'uiauto/listeners/base_listener'
|
2
|
+
|
3
|
+
module UIAuto
|
4
|
+
module Listeners
|
5
|
+
class ExitStatusListener < BaseListener
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@result = 0
|
9
|
+
end
|
10
|
+
|
11
|
+
def log_fail(message)
|
12
|
+
@result = 1 unless @result == 2
|
13
|
+
end
|
14
|
+
|
15
|
+
def log_error(message)
|
16
|
+
@result = 2
|
17
|
+
end
|
18
|
+
|
19
|
+
def result
|
20
|
+
@result
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module UIAuto
|
2
|
+
class Reporter
|
3
|
+
def initialize
|
4
|
+
@listeners = []
|
5
|
+
@element_tree = ""
|
6
|
+
end
|
7
|
+
|
8
|
+
def add_listener(listener)
|
9
|
+
@listeners << listener
|
10
|
+
end
|
11
|
+
|
12
|
+
def formatter=(formatter)
|
13
|
+
add_listener(formatter)
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse_instruments_output(output)
|
17
|
+
lines = output.split("\n")
|
18
|
+
lines.each do |line|
|
19
|
+
notify_listeners(:instruments_line, line)
|
20
|
+
case line
|
21
|
+
when /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} \+\d{4} (\w+): (.*)$/
|
22
|
+
log_type = $1
|
23
|
+
message = $2
|
24
|
+
|
25
|
+
notify_listeners("log_#{log_type.downcase}".to_sym, message)
|
26
|
+
when /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} \+\d{4} logElementTree:$/
|
27
|
+
@element_tree = ""
|
28
|
+
notify_listeners(:element_tree_start)
|
29
|
+
when /^UIATarget .+$/
|
30
|
+
@element_tree << line + "\n"
|
31
|
+
notify_listeners(:element_tree_line, line)
|
32
|
+
when /^elements: \{$/
|
33
|
+
@element_tree << line + "\n"
|
34
|
+
notify_listeners(:element_tree_line, line)
|
35
|
+
when /^\t+.+$/
|
36
|
+
@element_tree << line + "\n"
|
37
|
+
notify_listeners(:element_tree_line, line)
|
38
|
+
when /^\}$/
|
39
|
+
@element_tree << line
|
40
|
+
|
41
|
+
notify_listeners(:element_tree, @element_tree)
|
42
|
+
notify_listeners(:element_tree_line, line)
|
43
|
+
notify_listeners(:element_tree_finish)
|
44
|
+
when /^Instruments Trace Complete \(Duration : (.+); Output : (.+)$/
|
45
|
+
duration = $1
|
46
|
+
trace_location = $2
|
47
|
+
|
48
|
+
notify_listeners(:script_summary, duration, trace_location)
|
49
|
+
else
|
50
|
+
notify_listeners(:unknown, line)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def run_start
|
56
|
+
notify_listeners(:run_start)
|
57
|
+
end
|
58
|
+
|
59
|
+
def run_finish
|
60
|
+
notify_listeners(:run_finish)
|
61
|
+
end
|
62
|
+
|
63
|
+
def script_start(script)
|
64
|
+
notify_listeners(:script_start, script)
|
65
|
+
end
|
66
|
+
|
67
|
+
def script_finish(script)
|
68
|
+
notify_listeners(:script_finish, script)
|
69
|
+
end
|
70
|
+
|
71
|
+
def load_simulator_data(data)
|
72
|
+
notify_listeners(:load_simulator_data, data)
|
73
|
+
end
|
74
|
+
|
75
|
+
protected
|
76
|
+
|
77
|
+
def notify_listeners(event, *args)
|
78
|
+
@listeners.each do |listener|
|
79
|
+
listener.send(event, *args)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/uiauto/runner.rb
CHANGED
@@ -1,42 +1,60 @@
|
|
1
1
|
require 'uiauto/instruments'
|
2
2
|
require 'uiauto/simulator'
|
3
|
+
require 'uiauto/reporter'
|
4
|
+
require 'uiauto/formatters'
|
5
|
+
require 'uiauto/listeners'
|
3
6
|
|
4
7
|
module UIAuto
|
5
8
|
class Runner
|
6
9
|
def self.run(file_or_dir, options = {})
|
10
|
+
if options[:require]
|
11
|
+
require File.expand_path(options[:require])
|
12
|
+
end
|
13
|
+
|
14
|
+
@reporter = Reporter.new
|
15
|
+
@exit_status_listener = Listeners::ExitStatusListener.new
|
16
|
+
@reporter.add_listener(@exit_status_listener)
|
17
|
+
|
18
|
+
listeners = options[:listeners] || []
|
19
|
+
listeners.each do |listener|
|
20
|
+
@reporter.add_listener(listener)
|
21
|
+
end
|
22
|
+
|
23
|
+
formatter = eval("Formatters::#{options[:format]}.new")
|
24
|
+
@reporter.formatter = formatter
|
25
|
+
|
26
|
+
@reporter.run_start
|
27
|
+
|
7
28
|
exit_status = 0
|
8
29
|
if file_or_dir.nil?
|
9
|
-
|
30
|
+
self.run_one options
|
10
31
|
elsif File.directory?(file_or_dir)
|
11
|
-
|
32
|
+
self.run_all(file_or_dir, options)
|
12
33
|
else
|
13
|
-
|
34
|
+
self.run_one(file_or_dir, options)
|
14
35
|
end
|
15
36
|
|
16
|
-
|
37
|
+
@reporter.run_finish
|
38
|
+
|
39
|
+
exit @exit_status_listener.result
|
17
40
|
end
|
18
41
|
|
19
42
|
private
|
20
43
|
|
21
44
|
def self.run_one(script, options)
|
45
|
+
relative_path = File.expand_path(script).sub(File.expand_path('.') + '/', '')
|
46
|
+
@reporter.script_start(relative_path)
|
22
47
|
self.process_comment_header script
|
23
|
-
instruments = Instruments.new(script, options)
|
24
|
-
|
25
|
-
|
26
|
-
exit_status
|
48
|
+
instruments = Instruments.new(script, @reporter, options)
|
49
|
+
instruments.execute
|
50
|
+
@reporter.script_finish(relative_path)
|
27
51
|
end
|
28
52
|
|
29
53
|
def self.run_all(dir, options)
|
30
|
-
exit_status = 0
|
31
54
|
scripts = Dir.glob(File.join(dir, "*.js"))
|
32
55
|
scripts.each do |script|
|
33
|
-
|
34
|
-
if script_exit_status > exit_status
|
35
|
-
exit_status = script_exit_status
|
36
|
-
end
|
56
|
+
self.run_one(script, options)
|
37
57
|
end
|
38
|
-
|
39
|
-
exit_status
|
40
58
|
end
|
41
59
|
|
42
60
|
def self.process_comment_header(script)
|
@@ -48,6 +66,8 @@ module UIAuto
|
|
48
66
|
full_path = File.expand_path(File.join(File.dirname(script), path))
|
49
67
|
end
|
50
68
|
|
69
|
+
relative_path = full_path.sub(File.expand_path('.') + '/', '')
|
70
|
+
@reporter.load_simulator_data(relative_path)
|
51
71
|
simulator = Simulator.new
|
52
72
|
simulator.load full_path
|
53
73
|
end
|
data/lib/uiauto/simulator.rb
CHANGED
@@ -3,6 +3,13 @@ require 'fileutils'
|
|
3
3
|
module UIAuto
|
4
4
|
class Simulator
|
5
5
|
CURRENT_IOS_SDK_VERSION = "6.1"
|
6
|
+
DEVICES = [
|
7
|
+
"iPad",
|
8
|
+
"iPad (Retina)",
|
9
|
+
"iPhone",
|
10
|
+
"iPhone (Retina 3.5-inch)",
|
11
|
+
"iPhone (Retina 4-inch)"
|
12
|
+
]
|
6
13
|
|
7
14
|
def initialize(sdk_version = CURRENT_IOS_SDK_VERSION)
|
8
15
|
@sdk_version = sdk_version
|
@@ -35,11 +42,19 @@ module UIAuto
|
|
35
42
|
`killall "iPhone Simulator" &> /dev/null || true`
|
36
43
|
end
|
37
44
|
|
38
|
-
def self.open
|
45
|
+
def self.open(simulator = nil)
|
39
46
|
xcode_path = `xcode-select -p`.strip
|
40
47
|
simulator_path = File.join(xcode_path, "/Platforms/iPhoneSimulator.platform/Developer/Applications/iPhone Simulator.app")
|
41
48
|
|
42
49
|
`open "#{simulator_path}"`
|
50
|
+
|
51
|
+
if DEVICES.include?(simulator)
|
52
|
+
uiauto_root = Gem::Specification.find_by_name("uiauto").gem_dir
|
53
|
+
choose_sim_device = File.join(uiauto_root, "helpers/choose_sim_device")
|
54
|
+
`#{choose_sim_device} "#{simulator}"`
|
55
|
+
elsif !simulator.nil?
|
56
|
+
puts "Invalid simulator: \"#{simulator}\""
|
57
|
+
end
|
43
58
|
end
|
44
59
|
|
45
60
|
private
|
data/lib/uiauto/version.rb
CHANGED
data/uiauto.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: uiauto
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Enriquez
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-09-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,6 +66,34 @@ dependencies:
|
|
66
66
|
- - '>='
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: childprocess
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rainbow
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
69
97
|
description: UI Automation script runner.
|
70
98
|
email:
|
71
99
|
- mike@enriquez.me
|
@@ -80,9 +108,20 @@ files:
|
|
80
108
|
- README.md
|
81
109
|
- Rakefile
|
82
110
|
- bin/uiauto
|
111
|
+
- helpers/choose_sim_device
|
83
112
|
- lib/uiauto.rb
|
84
113
|
- lib/uiauto/cli.rb
|
114
|
+
- lib/uiauto/formatters.rb
|
115
|
+
- lib/uiauto/formatters/README.md
|
116
|
+
- lib/uiauto/formatters/base_formatter.rb
|
117
|
+
- lib/uiauto/formatters/color_indent_formatter.rb
|
118
|
+
- lib/uiauto/formatters/instruments_formatter.rb
|
85
119
|
- lib/uiauto/instruments.rb
|
120
|
+
- lib/uiauto/listeners.rb
|
121
|
+
- lib/uiauto/listeners/README.md
|
122
|
+
- lib/uiauto/listeners/base_listener.rb
|
123
|
+
- lib/uiauto/listeners/exit_status_listener.rb
|
124
|
+
- lib/uiauto/reporter.rb
|
86
125
|
- lib/uiauto/runner.rb
|
87
126
|
- lib/uiauto/simulator.rb
|
88
127
|
- lib/uiauto/version.rb
|