Class: RSpec::Signal::HtmlSummary
- Inherits:
-
Object
- Object
- RSpec::Signal::HtmlSummary
- Defined in:
- lib/rspec/signal/html_summary.rb
Overview
Recognises bulk HTML inside a failure message and replaces it with the handful of facts that actually diagnose it.
A request spec that expects one sentence and receives a Rails exception page produces a diff several thousand lines long whose opening hundred lines are the exception page's own CSS. Printing the start of that is worse than useless: it is the one part of the response guaranteed to be identical for every failure in the suite. So the expected value is left exactly as it was, the actual value is named as HTML and measured, and the title, headings and leading visible text are pulled out -- which on a Rails error page is the exception class and its message.
Regex only, deliberately. A DOM parser would be a new hard dependency for something that never has to be correct, only useful, and which is handed broken markup by definition.
Constant Summary collapse
- MARKER =
"[HTML document]"- MIN_TAGS =
5- SCAN_WINDOW =
4_000- MAX_FACT_CHARS =
160- MAX_FACTS =
4- DOCUMENT_START =
/\A\s*(?:<!doctype\s+html|<html[\s>])/i.freeze
- TAG =
%r{</?[a-z][a-z0-9]*(?:\s[^<>]*?)?/?>}im.freeze
- STRUCTURAL =
/<(?:html|head|body|div|table|section|main|article|p)\b/i.freeze
- QUOTED =
/"(?:[^"\\]|\\.)*"/m.freeze
- DIFF_LINE =
/\A(\s*)([-+])(.*)\z/m.freeze
- NOISE =
%r{<(script|style)\b[^>]*>.*?</\1>|<!--.*?-->}im.freeze
- TITLE =
%r{<title[^>]*>(.*?)</title>}im.freeze
- H1 =
%r{<h1[^>]*>(.*?)</h1>}im.freeze
- H2 =
%r{<h2[^>]*>(.*?)</h2>}im.freeze
- PRE =
%r{<pre[^>]*>(.*?)</pre>}im.freeze
- ESCAPES =
{ "n" => "\n", "t" => "\t", "r" => "\r", "e" => "\e", '"' => '"', "\\" => "\\" }.freeze
- ENTITIES =
{ "amp" => "&", "lt" => "<", "gt" => ">", "quot" => '"', "apos" => "'", "#39" => "'", "nbsp" => " " }.freeze
Instance Attribute Summary collapse
-
#byte_size ⇒ Object
readonly
Returns the value of attribute byte_size.
-
#line_count ⇒ Object
readonly
Returns the value of attribute line_count.
Class Method Summary collapse
- .html?(text) ⇒ Boolean
-
.reduce(lines, threshold:) ⇒ Array<String>
The same lines with bulk HTML replaced.
- .summarise(text, threshold) ⇒ HtmlSummary?
Instance Method Summary collapse
-
#facts ⇒ Object
[["Title", "Action Controller: Exception caught"], ...]. -
#initialize(html) ⇒ HtmlSummary
constructor
A new instance of HtmlSummary.
- #to_h ⇒ Object
- #to_lines ⇒ Object
Constructor Details
#initialize(html) ⇒ HtmlSummary
Returns a new instance of HtmlSummary.
151 152 153 154 155 |
# File 'lib/rspec/signal/html_summary.rb', line 151 def initialize(html) @html = html @line_count = html.count("\n") + 1 @byte_size = html.bytesize end |
Instance Attribute Details
#byte_size ⇒ Object (readonly)
Returns the value of attribute byte_size.
149 150 151 |
# File 'lib/rspec/signal/html_summary.rb', line 149 def byte_size @byte_size end |
#line_count ⇒ Object (readonly)
Returns the value of attribute line_count.
149 150 151 |
# File 'lib/rspec/signal/html_summary.rb', line 149 def line_count @line_count end |
Class Method Details
.html?(text) ⇒ Boolean
61 62 63 64 65 66 |
# File 'lib/rspec/signal/html_summary.rb', line 61 def html?(text) return true if DOCUMENT_START.match?(text) window = text[0, SCAN_WINDOW].to_s STRUCTURAL.match?(window) && window.scan(TAG).size >= MIN_TAGS end |
.reduce(lines, threshold:) ⇒ Array<String>
Returns the same lines with bulk HTML replaced.
47 48 49 |
# File 'lib/rspec/signal/html_summary.rb', line 47 def reduce(lines, threshold:) reduce_diff_runs(reduce_inline(lines, threshold), threshold) end |
.summarise(text, threshold) ⇒ HtmlSummary?
52 53 54 55 56 57 58 59 |
# File 'lib/rspec/signal/html_summary.rb', line 52 def summarise(text, threshold) return nil if text.length < threshold html = unescape(text) return nil unless html?(html) new(html) end |
Instance Method Details
#facts ⇒ Object
[["Title", "Action Controller: Exception caught"], ...]
158 159 160 |
# File 'lib/rspec/signal/html_summary.rb', line 158 def facts @facts ||= build_facts end |
#to_h ⇒ Object
168 169 170 |
# File 'lib/rspec/signal/html_summary.rb', line 168 def to_h { lines: line_count, bytes: byte_size }.merge(facts.to_h { |(label, value)| [label.downcase.to_sym, value] }) end |
#to_lines ⇒ Object
162 163 164 165 166 |
# File 'lib/rspec/signal/html_summary.rb', line 162 def to_lines ["[HTML document: #{number(line_count)} #{plural(line_count, "line")}, #{human_size} " \ "-- markup omitted]", *facts.map { |(label, value)| " #{label}: #{value}" }] end |