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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b13ad5de892dd0145639a2f46bfc12a3d6555535
4
- data.tar.gz: 0b3a7d825433f830e6bb0ced19bce989d033a28b
3
+ metadata.gz: 3afb5260e2a269072122eb099792ea8a95b27547
4
+ data.tar.gz: c120b7d250ce0524788a53404df05eac9321842e
5
5
  SHA512:
6
- metadata.gz: 8334839a2bf68692b91729130c0951d4d97837020709a23b32acf21d70ad2ee809c5d1c9644332e38f3fad2ed438983787c7071ed281043cfe17ec8957f845fc
7
- data.tar.gz: eacf0342d04567d12ee38caf0402567631f9ad46a31ca0a6d77aa4307cf685cc24121363d6d37483d3ddf4db54de742a2d79b080b55f93014828e562c815fa8d
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 to run on the simulator. 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.
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
- [--device=DEVICE]
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
@@ -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, :default => File.expand_path("./uiauto/results")
44
- method_option :trace, :default => File.expand_path("./uiauto/results/trace")
45
- method_option :app
46
- method_option :device
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", "manage simulator data"
74
+ desc "simulator SUBCOMMAND ...ARGS", "Manage simulator data"
52
75
  subcommand "simulator", SimulatorCLI
53
76
  end
54
77
  end
@@ -0,0 +1,6 @@
1
+ require 'uiauto/formatters/base_formatter'
2
+ require 'uiauto/formatters/instruments_formatter'
3
+ require 'uiauto/formatters/color_indent_formatter'
4
+
5
+ module UIAuto::Formatters
6
+ 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,11 @@
1
+ require 'uiauto/listeners/base_listener'
2
+
3
+ module UIAuto
4
+ module Formatters
5
+ class BaseFormatter < Listeners::BaseListener
6
+ def output
7
+ STDOUT
8
+ end
9
+ end
10
+ end
11
+ end
@@ -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
@@ -0,0 +1,11 @@
1
+ require 'uiauto/formatters/base_formatter'
2
+
3
+ module UIAuto
4
+ module Formatters
5
+ class InstrumentsFormatter < BaseFormatter
6
+ def instruments_line(line)
7
+ output.puts line
8
+ end
9
+ end
10
+ end
11
+ end
@@ -1,17 +1,21 @@
1
- require 'pty'
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
- @script = script
11
- @trace = opts[:trace]
12
- @results = opts[:results]
13
- @device = opts[:device]
14
- @app = opts[:app] || default_application
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
- exit_status = 0
33
- read, write = PTY.open
34
- pid = spawn(command, :in => STDIN, :out => write, :err => write)
35
- write.close
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 = read.readpartial(8192)
40
- lines = buffer.split("\n")
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
- read.close
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,5 @@
1
+ require 'uiauto/listeners/base_listener'
2
+ require 'uiauto/listeners/exit_status_listener'
3
+
4
+ module UIAuto::Listeners
5
+ 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
@@ -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
- exit_status = self.run_one options
30
+ self.run_one options
10
31
  elsif File.directory?(file_or_dir)
11
- exit_status = self.run_all(file_or_dir, options)
32
+ self.run_all(file_or_dir, options)
12
33
  else
13
- exit_status = self.run_one(file_or_dir, options)
34
+ self.run_one(file_or_dir, options)
14
35
  end
15
36
 
16
- exit exit_status
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
- exit_status = instruments.execute
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
- script_exit_status = self.run_one(script, options)
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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module UIAuto
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -23,4 +23,6 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.add_dependency "CFPropertyList"
25
25
  spec.add_dependency "thor"
26
+ spec.add_dependency "childprocess"
27
+ spec.add_dependency "rainbow"
26
28
  end
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.1.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-08-22 00:00:00.000000000 Z
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