bauxite 0.6.5 → 0.6.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -53,6 +53,10 @@ module Bauxite
53
53
  # Number of seconds to wait before issuing a timeout error. This
54
54
  # timeout applies only to Selectors.
55
55
  #
56
+ # [-o, \--open_timeout SECONDS]
57
+ # Number of seconds to wait before issuing a timeout error. This
58
+ # timeout applies only to page loading times (i.e. Net::HTTP).
59
+ #
56
60
  # [-d, \--debug]
57
61
  # If an error occurs, break into the debug console. This mode is very
58
62
  # useful to try different selector combinations and debug
@@ -84,6 +88,8 @@ module Bauxite
84
88
  # To see a complete list of the available loggers execute:
85
89
  # bauxite -h
86
90
  #
91
+ # Note that multiple instances of this option can be specified.
92
+ #
87
93
  # [-L, \--logger-option OPTION]
88
94
  # A <tt>name=value</tt> pair of options that are directly forwarded to
89
95
  # the logger. This option argument can appear multiple times in the
@@ -106,12 +112,34 @@ module Bauxite
106
112
  # To see a complete list of the available selectors execute:
107
113
  # bauxite -h
108
114
  #
115
+ # [-c, \--capture]
116
+ # If the test fails, capture a screenshot in the +output+ directory.
117
+ # See the \--output option below.
118
+ #
119
+ # [\--csv-summary FILE]
120
+ # Output a single-line CSV summary ideal to feed into the Plot Jenkins
121
+ # plugin. If +FILE+ is not specified, defaults to +summary.csv+
122
+ #
123
+ # [\--output DIR]
124
+ # Output directory for generated artifacts. Defaults to the current
125
+ # working directory.
126
+ #
109
127
  # [-u, \--url URL]
110
128
  # This option is an alias of:
111
129
  # -p remote -P url=URL
112
130
  # If +URL+ is not present <tt>http://localhost:4444/wd/hub</tt> will be
113
131
  # assumed.
114
132
  #
133
+ # [\--jenkins DIR]
134
+ # Configures default options for Jenkins integration. This option is an
135
+ # alias of:
136
+ # -p remote -P url=http://localhost:4444/wd/hub -l echo -l html
137
+ # -L html_package=true -c --csv-summary
138
+ # --output DIR
139
+ # Note that any of the options above can be overridden by specifying the
140
+ # option after the <tt>--jenkins</tt> option. For example:
141
+ # --jenkins -u selenium.my-organization.com:4445
142
+ #
115
143
  # [-e, \--extension DIR]
116
144
  # Loads every Ruby file (*.rb) inside +DIR+ (and subdirectories). This
117
145
  # option can be used to load custom Bauxite extensions (e.g. Actions,
@@ -147,7 +175,7 @@ module Bauxite
147
175
  class Application
148
176
  def self.start #:nodoc:
149
177
  options = {
150
- :logger => (ENV['TERM'] == 'xterm') ? 'xterm' : 'terminal',
178
+ :logger => [],
151
179
  :verbose => false,
152
180
  :break => false,
153
181
  :driver => 'firefox',
@@ -160,7 +188,9 @@ module Bauxite
160
188
  :logger_opt => {},
161
189
  :extensions => []
162
190
  }
163
-
191
+
192
+ default_logger = (ENV['TERM'] == 'xterm') ? 'xterm' : 'terminal'
193
+
164
194
  OptionParser.new do |opts|
165
195
  opts.banner = "Usage: bauxite [options] [files...]"
166
196
 
@@ -173,13 +203,19 @@ module Bauxite
173
203
  end
174
204
  self
175
205
  end
176
- def opts.multi(*args)
206
+ def opts.hash(*args)
177
207
  on(*args[1..-1]) do |v|
178
208
  n,v = v.split('=', 2)
179
209
  @o[args[0]][n.to_sym] = v || true
180
210
  end
181
211
  self
182
212
  end
213
+ def opts.multi(*args)
214
+ on(*args[1..-1]) do |v|
215
+ @o[args[0]] << v
216
+ end
217
+ self
218
+ end
183
219
  opts.o = options
184
220
 
185
221
  opts.separator ""
@@ -191,23 +227,36 @@ module Bauxite
191
227
  .single(:debug , "-d", "--debug", "Break to debug on error. "+
192
228
  "Start the debug console if no input files given.")
193
229
  .single(:driver , "-p", "--provider PROVIDER" , "Driver provider")
194
- .multi( :driver_opt , "-P", "--provider-option OPTION", "Provider options (name=value)")
195
- .single(:logger , "-l", "--logger LOGGER" , "Logger type ('#{options[:logger]}')")
196
- .multi( :logger_opt , "-L", "--logger-option OPTION" , "Logger options (name=value)")
230
+ .hash( :driver_opt , "-P", "--provider-option OPTION", "Provider options (name=value)")
231
+ .multi( :logger , "-l", "--logger LOGGER" , "Logger type ('#{default_logger}')")
232
+ .hash( :logger_opt , "-L", "--logger-option OPTION" , "Logger options (name=value)")
197
233
  .single(:reset , "-r", "--reset" , "Reset driver between tests")
198
234
  .single(:wait , "-w", "--wait" , "Wait for ENTER before exiting")
199
235
  .single(:selector , "-s", "--selector SELECTOR" , "Default selector ('#{options[:selector]}')")
200
236
  .single(:capture , "-c", "--capture" , "If the test fails, capture a screenshot")
201
- .single(:csv , "--csv-summary FILE" , "Output a single-line CSV summary")
202
237
  .single(:output , "--output DIR" , "Output directory for generated artifacts")
203
- opts.on("-u", "--url [URL]", "Configure the remote provider listening in the given url.") do |v|
238
+ .multi( :extensions , "-e", "--extension DIR" , "Load extensions from DIR")
239
+
240
+ opts.on("-u", "--url [URL]", "Configure the remote provider listening in the given url") do |v|
204
241
  v = 'localhost:4444' unless v
205
242
  v = 'http://'+v unless v.match /^https?:\/\//
206
243
  v = v + '/wd/hub' unless v.end_with? '/wd/hub'
207
244
  options[:driver] = 'remote'
208
245
  options[:driver_opt][:url] = v
209
246
  end
210
- opts.on("-e", "--extension DIR", "Load extensions from DIR") { |v| options[:extensions] << v }
247
+
248
+ opts.on("--csv-summary [FILE]", "Output a single-line CSV summary") { |v| options[:csv] = v || 'summary.csv' }
249
+
250
+ opts.on("--jenkins DIR", "Configure default options for Jenkins integration") do |v|
251
+ options[:driver] = 'remote'
252
+ options[:driver_opt][:url] = 'http://localhost:4444/wd/hub'
253
+ options[:logger] = ['echo', 'html']
254
+ options[:output] = v
255
+ options[:logger_opt][:html_package] = true
256
+ options[:capture] = true
257
+ options[:csv] = 'summary.csv'
258
+ end
259
+
211
260
  opts.on("--version", "Show version") do
212
261
  puts "bauxite #{Bauxite::VERSION}"
213
262
  exit
@@ -232,7 +281,9 @@ module Bauxite
232
281
 
233
282
  opts.separator ""
234
283
  end.parse!
235
-
284
+
285
+ options[:logger] << default_logger unless options[:logger].size > 0
286
+
236
287
  ctx = nil
237
288
  begin
238
289
  ctx = Context.new(options)
@@ -273,7 +324,7 @@ module Bauxite
273
324
  ok = ctx.tests.inject(0) { |s,t| s + (t[:status] == 'OK' ? 1 : 0) }
274
325
  failed = total - ok
275
326
  time = ctx.tests.inject(0) { |s,t| s + t[:time] }
276
- File.open(csv_file, 'w') do |f|
327
+ File.open(ctx.output_path(csv_file), 'w') do |f|
277
328
  f.write "Total,OK,Failed,Time\n#{total},#{ok},#{failed},#{time}\n"
278
329
  end
279
330
  end
@@ -23,6 +23,7 @@
23
23
  require 'selenium-webdriver'
24
24
  require 'readline'
25
25
  require 'csv'
26
+ require 'pathname'
26
27
 
27
28
  # Load dependencies and extensions without leaking dir into the global scope
28
29
  lambda do
@@ -177,7 +178,12 @@ module Bauxite
177
178
  # # and clicks the "Search" button.
178
179
  #
179
180
  def start(actions = [])
180
- _load_driver
181
+ begin
182
+ _load_driver
183
+ rescue StandardError => e
184
+ print_error(e)
185
+ raise
186
+ end
181
187
  return unless actions.size > 0
182
188
  begin
183
189
  actions.each do |action|
@@ -420,7 +426,13 @@ module Bauxite
420
426
  # Constructs a Logger instance using +name+ as a hint for the logger
421
427
  # type.
422
428
  #
423
- def self.load_logger(name, options)
429
+ def self.load_logger(loggers, options)
430
+ if loggers.is_a? Array
431
+ return Loggers::CompositeLogger.new(options, loggers)
432
+ end
433
+
434
+ name = loggers
435
+
424
436
  log_name = (name || 'null').downcase
425
437
 
426
438
  class_name = "#{log_name.capitalize}Logger"
@@ -555,6 +567,29 @@ module Bauxite
555
567
  end
556
568
  end
557
569
 
570
+ # Returns the output path for +path+ accounting for the
571
+ # <tt>__OUTPUT__</tt> variable.
572
+ #
573
+ # For example:
574
+ # # assuming --output /mnt/disk
575
+ #
576
+ # ctx.output_path '/tmp/myfile.txt'
577
+ # # => returns '/tmp/myfile.txt'
578
+ #
579
+ # ctx.output_path 'myfile.txt'
580
+ # # => returns '/mnt/disk/myfile.txt'
581
+ #
582
+ def output_path(path)
583
+ unless Pathname.new(path).absolute?
584
+ output = @variables['__OUTPUT__']
585
+ if output
586
+ Dir.mkdir output unless Dir.exists? output
587
+ path = File.join(output, path)
588
+ end
589
+ end
590
+ path
591
+ end
592
+
558
593
  # ======================================================================= #
559
594
  # :section: Metadata
560
595
  # ======================================================================= #
@@ -24,19 +24,23 @@
24
24
  #
25
25
  # This composite logger forwards logging calls to each of its children.
26
26
  #
27
- # Set the +:loggers+ option to a comma-separated list of logger names
27
+ # Composite logger options include:
28
+ # [<tt>loggers</tt>] A comma-separated list of logger names.
28
29
  #
29
30
  class Bauxite::Loggers::CompositeLogger
30
31
 
31
32
  # Constructs a new composite logger instance.
32
- def initialize(options)
33
- unless options[:loggers]
34
- raise ArgumentError, "Missing required logger option 'loggers'. "+
35
- "The value of this option is a comma-separated list of valid loggers. "+
36
- "For example loggers=xterm,file."
33
+ def initialize(options, loggers = nil)
34
+ unless loggers
35
+ unless options[:loggers]
36
+ raise ArgumentError, "Missing required logger option 'loggers'. "+
37
+ "The value of this option is a comma-separated list of valid loggers. "+
38
+ "For example loggers=xterm,file."
39
+ end
40
+ loggers = options[:loggers].split(',')
37
41
  end
38
42
 
39
- @loggers = options[:loggers].split(',').map do |l|
43
+ @loggers = loggers.map do |l|
40
44
  Bauxite::Context::load_logger(l, options)
41
45
  end
42
46
  end
@@ -25,6 +25,10 @@
25
25
  # This logger outputs the raw action text for every action executed to
26
26
  # the file specified in the +file+ logger option.
27
27
  #
28
+ # File logger options include:
29
+ # [<tt>file</tt>] Output file name.
30
+ #
31
+ #
28
32
  class Bauxite::Loggers::FileLogger < Bauxite::Loggers::NullLogger
29
33
 
30
34
  # Constructs a new echo logger instance.
@@ -34,12 +38,17 @@ class Bauxite::Loggers::FileLogger < Bauxite::Loggers::NullLogger
34
38
  unless @file and @file != ''
35
39
  raise ArgumentError, "FileLogger configuration error: Undefined 'file' option."
36
40
  end
37
- File.open(@file, "w") {} # truncate file
41
+ @lines = []
42
+ end
43
+
44
+ # Completes the log execution.
45
+ def finalize(ctx)
46
+ File.open(ctx.output_path(@file), 'w') { |f| f.write(@lines.join("\n")) }
38
47
  end
39
48
 
40
49
  # Echoes the raw action text.
41
50
  def log_cmd(action)
42
- File.open(@file, 'a+') { |f| f.write(action.text+"\n") }
51
+ @lines << action.text
43
52
  yield
44
53
  end
45
54
  end
@@ -20,12 +20,20 @@
20
20
  # SOFTWARE.
21
21
  #++
22
22
 
23
- # Echo logger.
23
+ require 'base64'
24
+
25
+ # Html logger.
24
26
  #
25
- # This logger outputs the raw action text for every action executed.
27
+ # This logger creates an HTML report of the test execution, linking to the
28
+ # captures taken, if any.
26
29
  #
27
- # Note that this logger does not include execution status information
28
- # (i.e. action succeeded, failed or was skipped).
30
+ # Html logger options include:
31
+ # [<tt>html</tt>] Name of the outpus HTML report file. If not present, defaults
32
+ # to "test.html".
33
+ # [<tt>html_package</tt>] If set, embed captures into the HTML report file
34
+ # using the data URI scheme (base64 encoded). The
35
+ # captures embedded into the report are deleted from
36
+ # the filesystem.
29
37
  #
30
38
  class Bauxite::Loggers::HtmlLogger < Bauxite::Loggers::NullLogger
31
39
 
@@ -35,6 +43,7 @@ class Bauxite::Loggers::HtmlLogger < Bauxite::Loggers::NullLogger
35
43
  super(options)
36
44
  @data = []
37
45
  @file = options[:html] || 'test.html'
46
+ @imgs = []
38
47
  end
39
48
 
40
49
  # Logs the specified string.
@@ -158,12 +167,9 @@ class Bauxite::Loggers::HtmlLogger < Bauxite::Loggers::NullLogger
158
167
  html << "
159
168
  </body>
160
169
  </html>"
161
- file = @file
162
- if output != ''
163
- file = File.join(output, file)
164
- Dir.mkdir output unless Dir.exists? output
165
- end
170
+ file = ctx.output_path(@file)
166
171
  File.open(file, 'w') { |f| f.write html }
172
+ File.delete(*@imgs) if @imgs.size > 0
167
173
  end
168
174
 
169
175
  private
@@ -171,7 +177,13 @@ private
171
177
  "\n"+depth.times.inject('') { |s,i| s + "\t" } + s
172
178
  end
173
179
  def _img(output, path)
174
- path = path[output.size+1..-1] unless output == ''
175
- "<img src='#{path}'/>"
180
+ if @options[:html_package]
181
+ content = Base64.encode64(File.open(path, 'r') { |f| f.read })
182
+ @imgs << path unless @imgs.include? path
183
+ "<img src='data:image/png;base64,#{content}'/>"
184
+ else
185
+ path = path[output.size+1..-1] unless output == ''
186
+ "<img src='#{path}'/>"
187
+ end
176
188
  end
177
189
  end
@@ -27,6 +27,14 @@ require_relative 'terminal'
27
27
  # This logger outputs colorized lines using xterm (VT100/2) escape
28
28
  # sequences.
29
29
  #
30
+ # XTerm logger options include:
31
+ # [<tt>nc</tt>, <tt>color</tt>] If set to 'no', prints text without using
32
+ # colors. Note that positional escape sequences
33
+ # will still be used to show progress. To disable
34
+ # escape sequences completely, consider using the
35
+ # Bauxite::Loggers::TerminalLogger logger
36
+ # instead.
37
+ #
30
38
  class Bauxite::Loggers::XtermLogger < Bauxite::Loggers::TerminalLogger
31
39
 
32
40
  protected
data/lib/bauxite.rb CHANGED
@@ -22,7 +22,7 @@
22
22
 
23
23
  #--
24
24
  module Bauxite
25
- VERSION = "0.6.5"
25
+ VERSION = "0.6.6"
26
26
  end
27
27
  #++
28
28
 
data/test/asserth.bxt CHANGED
@@ -1,2 +1,2 @@
1
1
  open "https://www.ruby-lang.org"
2
- asserth "content-type=html" "content-length=^\d+$"
2
+ asserth "content-type=html" "status=^\d+ .*$"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bauxite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.5
4
+ version: 0.6.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Patricio Zavolinsky
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-06 00:00:00.000000000 Z
11
+ date: 2014-02-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: selenium-webdriver