Packages
espec
1.2.0
1.10.0
1.9.2
1.9.1
1.9.0
1.8.3
1.8.2
1.8.1
1.8.0
1.7.0
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.1
1.5.0
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.2
1.2.1
1.2.0
1.1.2
1.1.1
1.1.0
1.0.1
1.0.0
0.8.28
0.8.27
0.8.26
0.8.25
0.8.24
0.8.23
0.8.22
0.8.21
0.8.20
0.8.19
0.8.18
0.8.17
0.8.16
0.8.15
0.8.14
0.8.13
0.8.12
0.8.11
0.8.10
0.8.9
0.8.8
0.8.7
0.8.6
0.8.5
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.1
0.5.0
0.4.2
0.4.1
0.4.0
0.3.7
0.3.5
0.3.0
0.2.0
0.1.0
BDD testing framework for Elixir inspired by RSpec.
Current section
Files
Jump to
Current section
Files
lib/espec/output/html.ex
defmodule ESpec.Output.Html do
@moduledoc """
Generates html output.
"""
alias ESpec.Example
@doc "Format the final result."
def format_result(examples, times, _opts) do
tree = context_tree(examples)
html = make_html(tree, true)
summary = format_summary(examples, times)
string = EEx.eval_file(template_path(), [examples: html, summary: summary])
String.replace(string, "\n", "")
end
@doc "Formats an example result."
def format_example(_example, _opts), do: ""
defp template_path, do: Path.join(Path.dirname(__ENV__.file), "templates/html.html.eex")
defp context_tree(examples) do
examples
|> Enum.reduce({Map.new, []}, fn(ex, acc) ->
contexts = Enum.filter(ex.context, &(&1.__struct__ == ESpec.Context))
put_deep(acc, contexts, ex)
end)
end
defp put_deep({dict, values}, [el | tl], value) when length(tl) > 0 do
d = case Map.get(dict, el) do
{inner, vals} -> put_deep({inner, vals}, tl, value)
nil -> put_deep({Map.new, []}, tl, value)
end
{Map.put(dict, el, d), values}
end
defp put_deep({dict, values}, [el], value) do
new_dict = case Map.get(dict, el) do
{inner, vals} -> Map.put(dict, el, {inner, [value | vals]})
nil -> Map.put(dict, el, {Map.new, [value]})
end
{new_dict, values}
end
defp put_deep({dict, values}, [], value) do
{dict, [value | values]}
end
defp make_html({dict, values}, top? \\ false, firstli? \\ false) do
values
|> main_lis
|> ul_or_lis(firstli?)
|> uls(dict, top?, firstli?)
end
defp main_lis(values) do
Enum.reduce(values, "", fn(ex, acc) ->
acc <> "<li class='#{li_class(ex)}'>#{ex_desc(ex)}</li>"
end)
end
defp ul_or_lis(lis, firstli?) do
if String.length(lis) > 0 do
if firstli?, do: "<ul class='tree'>" <> lis <> "</ul>", else: "<ul>" <> lis <> "</ul>"
else
lis
end
end
defp uls(lis, dict, top?, firstli?) do
Enum.reduce(dict, lis, fn({key, d}, acc) ->
if top? do
acc <> "<section class='context'><h3>#{key.description}</h3>" <> make_html(d, false, true) <> "</section>"
else
mainli = "<li><h4>#{key.description}</h4>"
if firstli? do
acc <> "<ul class='tree'>#{mainli}" <> make_html(d) <> "</li></ul>"
else
acc <> "<ul>#{mainli}" <> make_html(d) <> "</li></ul>"
end
end
end)
end
defp ex_desc(ex) do
res = if String.length(ex.description) > 0 do
ex.description
else
if ex.status == :failure, do: ex.error.message, else: ex.result
end
res = "#{res} (#{ex.duration} ms)"
String.replace(res, "\"", "'")
end
defp li_class(ex), do: ex.status
defp format_summary(examples, {start_loading_time, finish_loading_time, finish_specs_time}) do
pending = Example.pendings(examples)
failed = Example.failure(examples)
load_time = :timer.now_diff(finish_loading_time, start_loading_time)
spec_time = :timer.now_diff(finish_specs_time, finish_loading_time)
seed = get_seed()
{
Enum.count(examples), Enum.count(failed), Enum.count(pending),
us_to_sec(load_time + spec_time), us_to_sec(load_time), us_to_sec(spec_time),
seed
}
end
defp us_to_sec(us), do: div(us, 10_000) / 100
defp get_seed do
if ESpec.Configuration.get(:order) do
false
else
ESpec.Configuration.get(:seed)
end
end
end