lib/bauxite/loggers/html.rb in bauxite-0.6.18 vs lib/bauxite/loggers/html.rb in bauxite-0.6.19
- old
+ new
@@ -1,154 +1,154 @@
-#--
-# Copyright (c) 2014 Patricio Zavolinsky
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-#++
-
-require 'base64'
-
-# Html logger.
-#
-# This logger creates an HTML report of the test execution, linking to the
-# captures taken, if any.
-#
-# Html logger options include:
-# [<tt>html</tt>] Name of the outpus HTML report file. If not present, defaults
-# to "test.html".
-# [<tt>html_package</tt>] If set, embed captures into the HTML report file
-# using the data URI scheme (base64 encoded). The
-# captures embedded into the report are deleted from
-# the filesystem.
-#
-class Bauxite::Loggers::HtmlLogger < Bauxite::Loggers::ReportLogger
-
- # Constructs a new null logger instance.
- #
- def initialize(options)
- super(options)
- @file = options[:html] || 'test.html'
- @imgs = []
- end
-
- # Completes the log execution.
- #
- def finalize(ctx)
- output = ctx.variables['__OUTPUT__'] || ''
-
- html = "<!DOCTYPE html>
-<html>
- <head>
- <style type='text/css'>
- body { font: 10pt sans-serif; }
- .action div { display: inline-block; }
- .cmd { width: 100px }
- .status { float: right; text-align: center; }
- .status .text { width: 100px; font-weight: bold }
- .test { background-color: #DFDFFF; margin-top: 20px }
- .ok .status .text { background-color: #DFFFDF }
- .error .status .text { background-color: #FFDFDF }
- .skip .status .text { background-color: #FFDFFF }
- .capture { border: 1px solid black }
- .capture img { max-width: 100% }
- .odd { background-color: #EEEEEE }
- .summary th { background-color: #DFDFFF; text-align: left }
- .summary td { cursor: pointer; }
- .top { position: absolute; top: 0px; right: 0px; background-color: #DFDFFF; padding: 5px; border-radius: 0px 0px 0px 5px; }
-
- </style>
- <script type='text/javascript'>
- function show(target) {
- var e = document.getElementById(target+'_content');
- window.location.href = '#'+target;
- }
- </script>
- </head>
- <body>"
- html << _d(2, "<div class='top'>Created using <a href='https://github.com/pzavolinsky/bauxite'>bauxite</a> on #{Time.new}</div>")
- if ctx.tests.any?
- html << _d(2, "<h1>Test Summary</h1>")
- html << _d(2, "<table class='summary'>")
- html << _d(3, "<tr><th>Name</th><th>Time</th><th>Status</th><th>Error</th></tr>")
-
- ctx.tests.each_with_index do |t,idx|
- error = t[:error]
- error = error ? error.message : ''
- html << _d(3, "<tr class='#{t[:status].downcase} #{(idx % 2) == 1 ? 'odd' : 'even'}' onclick='show(\"#{t[:name]}\")'>")
- html << _d(4, "<td>#{t[:name]}</td><td>#{t[:time].round(2)}</td><td class='status'>#{t[:status]}</td><td>#{error}</td>")
- html << _d(3, "</tr>")
- end
-
- html << _d(2, "</table>")
- end
-
- html << _d(2, "<h1>Test Details</h1>")
- @data.each do |test|
- name = test[:name]
- status = test[:actions].find { |a| a[:status] == :error } ? :error : :ok
- html << _d(2, "<a name='#{name}'></a>")
- html << _d(2, "<div class='test #{status}'>#{name}<div class='status'><div class='text'>#{status.upcase}</div></div></div>")
- html << _d(2, "<div id='#{name}_content' class='test-content'>")
-
- test[:actions].each_with_index do |action,idx|
- html << _d(3, "<div class='action #{action[:status]} #{(idx % 2) == 1 ? 'odd' : 'even'}'>")
- html << _d(4, "<div class='cmd'>#{action[:cmd]}</div>")
- html << _d(4, "<div class='args'>#{action[:args].join(' ')}</div>")
- html << _d(4, "<div class='status'>")
- html << _d(5, "<div class='time'>(#{action[:time].round(2).to_s}s)</div>")
- html << _d(5, "<div class='text'>#{action[:status].upcase}</div>")
- html << _d(4, "</div>")
- html << _d(3, "</div>")
- capture = action[:capture]
- if capture
- html << _d(3, "<div class='capture'>#{_img(output, capture)}</div>")
- end
- end
-
- item = ctx.tests.find { |t| t[:name] == name }
- if item and item[:error]
- capture = item[:error].variables['__CAPTURE__']
- if capture
- html << _d(3, "<div class='capture'>#{_img(output, capture)}</div>")
- end
- end
-
- html << _d(2, "</div>")
- end
- html << "
- </body>
-</html>"
- file = ctx.output_path(@file)
- File.open(file, 'w') { |f| f.write html }
- File.delete(*@imgs) if @imgs.size > 0
- end
-
-private
- def _d(depth, s)
- "\n"+depth.times.inject('') { |s,i| s + "\t" } + s
- end
- def _img(output, path)
- if @options[:html_package]
- content = Base64.encode64(File.open(path, 'r') { |f| f.read })
- @imgs << path unless @imgs.include? path
- "<img src='data:image/png;base64,#{content}'/>"
- else
- path = path[output.size+1..-1] unless output == ''
- "<img src='#{path}'/>"
- end
- end
-end
\ No newline at end of file
+#--
+# Copyright (c) 2014 Patricio Zavolinsky
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#++
+
+require 'base64'
+
+# Html logger.
+#
+# This logger creates an HTML report of the test execution, linking to the
+# captures taken, if any.
+#
+# Html logger options include:
+# [<tt>html</tt>] Name of the outpus HTML report file. If not present, defaults
+# to "test.html".
+# [<tt>html_package</tt>] If set, embed captures into the HTML report file
+# using the data URI scheme (base64 encoded). The
+# captures embedded into the report are deleted from
+# the filesystem.
+#
+class Bauxite::Loggers::HtmlLogger < Bauxite::Loggers::ReportLogger
+
+ # Constructs a new null logger instance.
+ #
+ def initialize(options)
+ super(options)
+ @file = options[:html] || 'test.html'
+ @imgs = []
+ end
+
+ # Completes the log execution.
+ #
+ def finalize(ctx)
+ output = ctx.variables['__OUTPUT__'] || ''
+
+ html = "<!DOCTYPE html>
+<html>
+ <head>
+ <style type='text/css'>
+ body { font: 10pt sans-serif; }
+ .action div { display: inline-block; }
+ .cmd { width: 100px }
+ .status { float: right; text-align: center; }
+ .status .text { width: 100px; font-weight: bold }
+ .test { background-color: #DFDFFF; margin-top: 20px }
+ .ok .status .text { background-color: #DFFFDF }
+ .error .status .text { background-color: #FFDFDF }
+ .skip .status .text { background-color: #FFDFFF }
+ .capture { border: 1px solid black }
+ .capture img { max-width: 100% }
+ .odd { background-color: #EEEEEE }
+ .summary th { background-color: #DFDFFF; text-align: left }
+ .summary td { cursor: pointer; }
+ .top { position: absolute; top: 0px; right: 0px; background-color: #DFDFFF; padding: 5px; border-radius: 0px 0px 0px 5px; }
+
+ </style>
+ <script type='text/javascript'>
+ function show(target) {
+ var e = document.getElementById(target+'_content');
+ window.location.href = '#'+target;
+ }
+ </script>
+ </head>
+ <body>"
+ html << _d(2, "<div class='top'>Created using <a href='https://github.com/pzavolinsky/bauxite'>bauxite</a> on #{Time.new}</div>")
+ if ctx.tests.any?
+ html << _d(2, "<h1>Test Summary</h1>")
+ html << _d(2, "<table class='summary'>")
+ html << _d(3, "<tr><th>Name</th><th>Time</th><th>Status</th><th>Error</th></tr>")
+
+ ctx.tests.each_with_index do |t,idx|
+ error = t[:error]
+ error = error ? error.message : ''
+ html << _d(3, "<tr class='#{t[:status].downcase} #{(idx % 2) == 1 ? 'odd' : 'even'}' onclick='show(\"#{t[:name]}\")'>")
+ html << _d(4, "<td>#{t[:name]}</td><td>#{t[:time].round(2)}</td><td class='status'>#{t[:status]}</td><td>#{error}</td>")
+ html << _d(3, "</tr>")
+ end
+
+ html << _d(2, "</table>")
+ end
+
+ html << _d(2, "<h1>Test Details</h1>")
+ @data.each do |test|
+ name = test[:name]
+ status = test[:actions].find { |a| a[:status] == :error } ? :error : :ok
+ html << _d(2, "<a name='#{name}'></a>")
+ html << _d(2, "<div class='test #{status}'>#{name}<div class='status'><div class='text'>#{status.upcase}</div></div></div>")
+ html << _d(2, "<div id='#{name}_content' class='test-content'>")
+
+ test[:actions].each_with_index do |action,idx|
+ html << _d(3, "<div class='action #{action[:status]} #{(idx % 2) == 1 ? 'odd' : 'even'}'>")
+ html << _d(4, "<div class='cmd'>#{action[:cmd]}</div>")
+ html << _d(4, "<div class='args'>#{action[:args].join(' ')}</div>")
+ html << _d(4, "<div class='status'>")
+ html << _d(5, "<div class='time'>(#{action[:time].round(2).to_s}s)</div>")
+ html << _d(5, "<div class='text'>#{action[:status].upcase}</div>")
+ html << _d(4, "</div>")
+ html << _d(3, "</div>")
+ capture = action[:capture]
+ if capture
+ html << _d(3, "<div class='capture'>#{_img(output, capture)}</div>")
+ end
+ end
+
+ item = ctx.tests.find { |t| t[:name] == name }
+ if item and item[:error]
+ capture = item[:error].variables['__CAPTURE__']
+ if capture
+ html << _d(3, "<div class='capture'>#{_img(output, capture)}</div>")
+ end
+ end
+
+ html << _d(2, "</div>")
+ end
+ html << "
+ </body>
+</html>"
+ file = ctx.output_path(@file)
+ File.open(file, 'w') { |f| f.write html }
+ File.delete(*@imgs) if @imgs.size > 0
+ end
+
+private
+ def _d(depth, s)
+ "\n"+depth.times.inject('') { |s,i| s + "\t" } + s
+ end
+ def _img(output, path)
+ if @options[:html_package]
+ content = Base64.encode64(File.open(path, 'rb') { |f| f.read })
+ @imgs << path unless @imgs.include? path
+ "<img src='data:image/png;base64,#{content}'/>"
+ else
+ path = path[output.size+1..-1] unless output == ''
+ "<img src='#{path}'/>"
+ end
+ end
+end