mirror of
https://gitea.invidious.io/iv-org/shard-spectator.git
synced 2024-08-15 00:53:35 +00:00
Initial code for HTML formatter
This commit is contained in:
parent
f4fc599a1d
commit
dd0ef01369
6 changed files with 178 additions and 1 deletions
|
@ -15,7 +15,7 @@ Spectator.describe Spectator do
|
||||||
|
|
||||||
it "handles multiple lines and examples" do
|
it "handles multiple lines and examples" do
|
||||||
# Offset is important.
|
# Offset is important.
|
||||||
expect(location.line).to eq(__LINE__ - 2)
|
expect(location.line).to eq(__LINE__ - 3)
|
||||||
# This line fails, refer to https://github.com/crystal-lang/crystal/issues/10562
|
# This line fails, refer to https://github.com/crystal-lang/crystal/issues/10562
|
||||||
# expect(location.end_line).to eq(__LINE__ + 2)
|
# expect(location.end_line).to eq(__LINE__ + 2)
|
||||||
# Offset is still important.
|
# Offset is still important.
|
||||||
|
|
|
@ -218,6 +218,15 @@ module Spectator
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Adds the HTML output option to the parser.
|
||||||
|
private def junit_option(parser, builder)
|
||||||
|
parser.on("--html_output OUTPUT_DIR", "Generate HTML output") do |output_dir|
|
||||||
|
Log.debug { "Setting output format to HTML (--html_output '#{output_dir}')" }
|
||||||
|
formatter = Formatting::HTMLFormatter.new(output_dir)
|
||||||
|
builder.add_formatter(formatter)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Adds the "no color" output option to the parser.
|
# Adds the "no color" output option to the parser.
|
||||||
private def no_color_option(parser, builder)
|
private def no_color_option(parser, builder)
|
||||||
parser.on("--no-color", "Disable colored output") do
|
parser.on("--no-color", "Disable colored output") do
|
||||||
|
|
85
src/spectator/formatting/html/body.ecr
Normal file
85
src/spectator/formatting/html/body.ecr
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
<div id="summary" class="<%= summary_result(report) %>">
|
||||||
|
<h1>Test Results</h1>
|
||||||
|
<span class="result <%= summary_result(report) %>"><% escape(Components::Totals.new(report.counts)) %></span>
|
||||||
|
<span class="elapsed" title="<% escape(report.runtime) %>"><% escape(runtime(report.runtime)) %></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%- if report.counts.fail > 0 -%>
|
||||||
|
<div id="failure-list">
|
||||||
|
<h2>Failures</h2>
|
||||||
|
<%- report.failures.each do |example| -%>
|
||||||
|
<div class="example fail">
|
||||||
|
<a href="#example-<%= example.object_id %>" title="Jump to result">
|
||||||
|
<h3 class="full-name"><% escape(example) %></h3>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<%- end -%>
|
||||||
|
</div>
|
||||||
|
<%- end -%>
|
||||||
|
|
||||||
|
<%- if report.counts.pending > 0 -%>
|
||||||
|
<div id="pending-list">
|
||||||
|
<h2>Pending</h2>
|
||||||
|
<%- report.pending.each do |example| -%>
|
||||||
|
<div class="example pending">
|
||||||
|
<a href="#example-<%= example.object_id %>" title="Jump to result">
|
||||||
|
<h3 class="full-name"><% escape(example) %></h3>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<%- end -%>
|
||||||
|
</div>
|
||||||
|
<%- end -%>
|
||||||
|
|
||||||
|
<div id="example-list">
|
||||||
|
<h2>Examples</h2>
|
||||||
|
<%- report.examples.each do |example| -%>
|
||||||
|
<div class="example <%= example.result %>">
|
||||||
|
<h3 id="#example-<%= example.object_id %>" class="full-name"><% escape(example) %></h3>
|
||||||
|
<span class="result <%= example.result %>"><%= example.result %></span>
|
||||||
|
<span class="elapsed" title="<% escape(example.result.elapsed) %>"><% escape(runtime(example.result.elapsed)) %></span>
|
||||||
|
<% if result = example.result.as?(PendingResult) %><span class="message"><% escape(result.reason) -%></span>
|
||||||
|
|
||||||
|
<%- elsif result = example.result.as?(ErrorResult) -%>
|
||||||
|
<span class="error">
|
||||||
|
<em><% escape(result.error.class) %></em>
|
||||||
|
<% escape(result.error.message) %>
|
||||||
|
</span>
|
||||||
|
<%- if backtrace = result.error.backtrace? -%>
|
||||||
|
<div class="stacktrace">
|
||||||
|
<%- backtrace.each do |line| -%>
|
||||||
|
<code class="backtrace-line<% unless line.starts_with?(/(src|spec)\//) %> muted<% end %>"><% escape(line) %></code>
|
||||||
|
<%- end -%>
|
||||||
|
</div>
|
||||||
|
<%- end -%>
|
||||||
|
|
||||||
|
<%- elsif result = example.result.as?(FailResult) -%>
|
||||||
|
<span class="error"><% escape(result.error.message) %></span>
|
||||||
|
<%- end -%>
|
||||||
|
|
||||||
|
<%- if example.result.expectations.empty? -%>
|
||||||
|
<span class="muted">No expectations reported</span>
|
||||||
|
<%- else -%>
|
||||||
|
<div class="expectation-list">
|
||||||
|
<%- example.result.expectations.each do |expectation| -%>
|
||||||
|
<div class="expectation <%= expectation.satisfied? ? "pass" : "fail" %>">
|
||||||
|
<h4><% escape(expectation.description) %></h4>
|
||||||
|
<%- if expectation.satisfied? -%>
|
||||||
|
<span class="result">pass</span>
|
||||||
|
<%- else -%>
|
||||||
|
<span class="result">fail</span>
|
||||||
|
<span class="message"><% escape(expectation.failure_message) %></span>
|
||||||
|
<dl class="expectation-values">
|
||||||
|
<%- expectation.values.each do |key, value| -%>
|
||||||
|
<dt><% escape(key) %></dt>
|
||||||
|
<dd><% escape(value) %></dd>
|
||||||
|
<%- end -%>
|
||||||
|
</dl>
|
||||||
|
<%- end -%>
|
||||||
|
<% if location = expectation.location? %><span class="location"><% escape(location) %></span><% end %>
|
||||||
|
</div>
|
||||||
|
<%- end -%>
|
||||||
|
</div>
|
||||||
|
<%- end -%>
|
||||||
|
</div>
|
||||||
|
<%- end -%>
|
||||||
|
</div>
|
2
src/spectator/formatting/html/foot.ecr
Normal file
2
src/spectator/formatting/html/foot.ecr
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
</body>
|
||||||
|
</html>
|
12
src/spectator/formatting/html/head.ecr
Normal file
12
src/spectator/formatting/html/head.ecr
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<!doctype html>
|
||||||
|
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
<title>Test Results</title>
|
||||||
|
<meta name="generator" content="Spectator">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
69
src/spectator/formatting/html_formatter.cr
Normal file
69
src/spectator/formatting/html_formatter.cr
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
require "ecr"
|
||||||
|
require "html"
|
||||||
|
require "./formatter"
|
||||||
|
|
||||||
|
module Spectator::Formatting
|
||||||
|
# Produces an HTML document with results of the test suite.
|
||||||
|
class HTMLFormatter < Formatter
|
||||||
|
# Default HTML file name.
|
||||||
|
private OUTPUT_FILE = "output.html"
|
||||||
|
|
||||||
|
# Output stream for the HTML file.
|
||||||
|
private getter! io : IO
|
||||||
|
|
||||||
|
# Creates the formatter.
|
||||||
|
# The *output_path* can be a directory or path of an HTML file.
|
||||||
|
# If the former, then an "output.html" file will be generated in the specified directory.
|
||||||
|
def initialize(output_path = OUTPUT_FILE)
|
||||||
|
@output_path = if output_path.ends_with?(".html")
|
||||||
|
output_path
|
||||||
|
else
|
||||||
|
File.join(output_path, OUTPUT_FILE)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Prepares the formatter for writing.
|
||||||
|
def start(_notification)
|
||||||
|
@io = File.open(@output_path, "w")
|
||||||
|
ECR.embed(__DIR__ + "/html/head.ecr", io)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Invoked after testing completes with summarized information from the test suite.
|
||||||
|
# All results are gathered at the end, then the report is generated.
|
||||||
|
def dump_summary(notification)
|
||||||
|
report = notification.report # ameba:disable Lint/UselessAssign
|
||||||
|
ECR.embed(__DIR__ + "/html/body.ecr", io)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Invoked at the end of the program.
|
||||||
|
# Allows the formatter to perform any cleanup and teardown.
|
||||||
|
def close
|
||||||
|
ECR.embed(__DIR__ + "/html/foot.ecr", io)
|
||||||
|
io.flush
|
||||||
|
io.close
|
||||||
|
end
|
||||||
|
|
||||||
|
private def escape(string)
|
||||||
|
HTML.escape(string.to_s, io)
|
||||||
|
end
|
||||||
|
|
||||||
|
private def runtime(span)
|
||||||
|
Components::Runtime.new(span).to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
private def totals(report)
|
||||||
|
Components::Totals.new(report.counts)
|
||||||
|
end
|
||||||
|
|
||||||
|
private def summary_result(report)
|
||||||
|
counts = report.counts
|
||||||
|
if counts.fail > 0
|
||||||
|
"fail"
|
||||||
|
elsif counts.pending > 0
|
||||||
|
"pending"
|
||||||
|
else
|
||||||
|
"pass"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue