Class: Arbre::RSpec::BeRenderedAsMatcher

Inherits:
Object
  • Object
show all
Defined in:
lib/arbre/rspec/be_rendered_as_matcher.rb

Overview

Used to match HTML snippets. HTML is canonized as much as possible, so that you don’t have to worry about whitespace or attribute order. Use ‘(…)’ as a wildcard. You may even place text in the wildcard for readability: ‘(… some wildcard …)’.

Examples

expect('<a href="test" target="_blank"/>').to \
  be_rendered_as('<a target="_blank" href="test" />') # => true
expect('<div><span></span><sub></sub></div>').to \
  be_rendered_as('<div>(...)</div>') # => true
expect('<div><span></span><sub></sub></div>').to \
  be_rendered_as('<div>(... a span here ...)<sub></sub></div>') # => true

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(expected, escape: true) ⇒ BeRenderedAsMatcher

Returns a new instance of BeRenderedAsMatcher.



20
21
22
23
# File 'lib/arbre/rspec/be_rendered_as_matcher.rb', line 20

def initialize(expected, escape: true)
  @expected = expected
  @escape = escape
end

Instance Attribute Details

#expectedObject (readonly)

Returns the value of attribute expected.



25
26
27
# File 'lib/arbre/rspec/be_rendered_as_matcher.rb', line 25

def expected
  @expected
end

Instance Method Details

#canonize_html(html) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/arbre/rspec/be_rendered_as_matcher.rb', line 44

def canonize_html(html)
  html = html.dup

  html.gsub! /(\s*[\n\r]\s*)+/, ' '
  html.gsub! /^\s+|\s+$/, ''
  html.gsub! /\s*(\/?>|<)\s*/, '\1'

  # Extract and order attributes.
  html.gsub! %r|(<[-_:\w].*?>)| do |all|
    all =~ %r|(<[-_:\w]+\s*)(.*?)(\s*/?>)|
    _, pre, attributes, post = $~.to_a

    has_wildcard = attributes =~ /\(\.\.\..*?(?:\.\.\.)?\)/ && attributes =~ /\w+/
    attributes = attributes.gsub(/\(\.\.\..*?(?:\.\.\.)?\)/, '') if has_wildcard
    attributes = attributes.scan(/(\(\.\.\..*?(?:\.\.\.)?\)|[-_:\w]+(?:=(?:".*?"|'.*?'|\S+))?)/).sort.join(' ')
    if has_wildcard
      attributes = "(...)#{attributes}(...)"
      pre.chomp! ' '
    end

    "#{pre}#{attributes}#{post}"
  end

  # Extract and order classes and styles
  html.gsub! %r[(class|style)="(.*?)"] do |all|
    all =~ %r[(class|style)="(.*?)"]

    attribute = $1
    items = $2.strip.split(/(;\s*|\s+)/).reject(&:blank?).sort.join(' ')
    %[#{attribute}="#{items}"]
  end

  html
end

#descriptionObject



27
28
29
# File 'lib/arbre/rspec/be_rendered_as_matcher.rb', line 27

def description
  "be rendered as #{expected}"
end

#failure_messageObject



79
80
81
82
83
84
85
# File 'lib/arbre/rspec/be_rendered_as_matcher.rb', line 79

def failure_message
  <<-MSG.gsub(/^\s{10}/, '')
    expected that element of type #{@actual.class} would be rendered differently:
      expected: #{expected.is_a?(Regexp) ? '/' + canonize_html(expected.source) + '/' : canonize_html(expected)} (#{expected.class})
           got: #{@actual.nil? ? 'nil' : canonize_html(ERB::Util.html_escape(@actual.to_s))}
  MSG
end

#failure_message_when_negatedObject



87
88
89
90
91
92
# File 'lib/arbre/rspec/be_rendered_as_matcher.rb', line 87

def failure_message_when_negated
  <<-MSG.gsub(/^\s{10}/, '')
    expected that element of type #{@actual.class} would not be rendered as #{canonize_html(expected)}, but it was:
      got: #{@actual.nil? ? 'nil' : canonize_html(ERB::Util.html_escape(@actual.to_s))}
  MSG
end

#matches?(actual) ⇒ Boolean

Returns:

  • (Boolean)


31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/arbre/rspec/be_rendered_as_matcher.rb', line 31

def matches?(actual)
  @actual = actual

  regexp = case expected
  when Regexp then Regexp.new(canonize_html(expected.source))
  else Regexp.new('^' + Regexp.escape(canonize_html(expected)).gsub(/\\\(\\\.\\\.\\\..*?(?:\\\.\\\.\\\.)?\\\)/, '.+') + '$')
  end

  html = actual.to_s
  html = ERB::Util.html_escape(html) if @escape
  canonize_html(html) =~ regexp
end