govspeak 3.6.2 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,69 @@
1
+ class HCardPresenter
2
+ def self.from_contact(contact)
3
+ new(contact_properties(contact), contact.country_code)
4
+ end
5
+
6
+ def self.contact_properties(contact)
7
+ { 'fn' => contact.recipient,
8
+ 'street-address' => contact.street_address,
9
+ 'postal-code' => contact.postal_code,
10
+ 'locality' => contact.locality,
11
+ 'region' => contact.region,
12
+ 'country-name' => country_name(contact) }
13
+ end
14
+
15
+ def self.country_name(contact)
16
+ contact.country_name unless contact.country_code == 'GB'
17
+ end
18
+
19
+ def self.property_keys
20
+ ['fn', 'street-address', 'postal-code', 'locality', 'region', 'country-name']
21
+ end
22
+
23
+ def self.address_formats
24
+ @address_formats ||= YAML.load_file('config/address_formats.yml')
25
+ end
26
+
27
+ attr_reader :properties, :country_code
28
+
29
+ def initialize(properties, country_code)
30
+ @properties = properties
31
+ @country_code = country_code
32
+ end
33
+
34
+ def render
35
+ "<p class=\"adr\">\n#{interpolate_address_template}\n</p>\n".html_safe
36
+ end
37
+
38
+ def interpolate_address_property(property_name)
39
+ value = properties[property_name]
40
+
41
+ if value.present?
42
+ "<span class=\"#{property_name}\">#{ERB::Util.html_escape(value)}</span>"
43
+ else
44
+ ""
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def interpolate_address_template
51
+ address = address_template
52
+
53
+ self.class.property_keys.each do |key|
54
+ address.gsub!(/\{\{#{key}\}\}/, interpolate_address_property(key))
55
+ end
56
+
57
+ address.gsub(/^\n/, '') # get rid of blank lines
58
+ .strip # get rid of any trailing whitespace
59
+ .gsub(/\n/, "<br />\n") # add break tags where appropriate
60
+ end
61
+
62
+ def address_template
63
+ (self.class.address_formats[country_code.to_s.downcase] || default_format_string).dup
64
+ end
65
+
66
+ def default_format_string
67
+ self.class.address_formats['gb']
68
+ end
69
+ end
@@ -0,0 +1,42 @@
1
+ <%
2
+ extra_class = []
3
+ extra_class << 'postal-address' if contact.has_postal_address?
4
+ %>
5
+ <div id="contact_<%= contact.id %>" class="<%= ['contact', extra_class].flatten.join(' ') %>">
6
+ <div class="content">
7
+ <h3><%= contact.title %></h3>
8
+ <div class="vcard contact-inner">
9
+ <% if contact.has_postal_address? %>
10
+ <%= render_hcard_address(contact) %>
11
+ <% end %>
12
+ <% if contact.email.present? || contact.contact_form_url.present? || contact.contact_numbers.any? %>
13
+ <div class="email-url-number">
14
+ <% if contact.email.present? %>
15
+ <p class="email">
16
+ <span class="type"><%= t('contact.email') %></span>
17
+ <a href="mailto:<%= contact.email %>" class="email"><%= contact.email %></a>
18
+ </p>
19
+ <% end %>
20
+ <% if contact.contact_form_url.present? %>
21
+ <p class="contact_form_url">
22
+ <span class="type"><%= t('contact.contact_form') %></span>
23
+ <a href="<%= contact.contact_form_url %>"><%= contact.contact_form_url.truncate(25) %></a>
24
+ </p>
25
+ <% end %>
26
+ <% contact.contact_numbers.each do |number| %>
27
+ <p class="tel">
28
+ <span class="type"><%= number.label %></span>
29
+ <%= number.number %>
30
+ </p>
31
+ <% end %>
32
+ </div>
33
+ <% end %>
34
+ <% if contact.comments.present? %>
35
+ <p class="comments"><%= auto_link(format_with_html_line_breaks(h(contact.comments))) %></p>
36
+ <% end %>
37
+ <% if contact.worldwide_organisation_path %>
38
+ <a href="<%= contact.worldwide_organisation_path %>">Access and opening times</a>
39
+ <% end %>
40
+ </div>
41
+ </div>
42
+ </div>
@@ -0,0 +1,91 @@
1
+ # encoding: UTF-8
2
+
3
+ require "test_helper"
4
+
5
+ class BlockquoteExtraQuoteRemoverTest < Minitest::Test
6
+ def assert_remover_transforms(options)
7
+ from = options.keys.first
8
+ to = options.values.first
9
+ assert_equal to, Govspeak::BlockquoteExtraQuoteRemover.remove(from)
10
+ end
11
+
12
+ def assert_leaves_untouched(candidate)
13
+ assert_remover_transforms candidate => candidate
14
+ end
15
+
16
+ test "ignores nil" do
17
+ assert_leaves_untouched nil
18
+ end
19
+
20
+ test "ignores text without double quotes" do
21
+ assert_leaves_untouched %{no quotes\na few lines,\n\n\n\nbut no quotes\n\n}
22
+ end
23
+
24
+ test "ignores text without a quote symbol" do
25
+ assert_leaves_untouched %{quotes\n"but not with a > symbol"}
26
+ end
27
+
28
+ test "transforms text with surrounding quotes" do
29
+ assert_remover_transforms(
30
+ %{He said:\n> "yes, it's true!"\n\napparently.} =>
31
+ %{He said:\n> yes, it's true!\n\napparently.}
32
+ )
33
+ end
34
+
35
+ test "leaves quotes in the middle of the string" do
36
+ assert_remover_transforms(
37
+ %{He said:\n> "yes, it's true!" whilst sipping a cocktail. "And yes, I did rather enjoy it." \n\napparently.} =>
38
+ %{He said:\n> yes, it's true!" whilst sipping a cocktail. "And yes, I did rather enjoy it.\n\napparently.}
39
+ )
40
+ end
41
+
42
+ test "leaves trailing text and quote intact" do
43
+ assert_remover_transforms(
44
+ %{He said:\n> "yes, it's true!" whilst sipping a cocktail.} =>
45
+ %{He said:\n> yes, it's true!" whilst sipping a cocktail.}
46
+ )
47
+ end
48
+
49
+ test "windows line breaks" do
50
+ assert_remover_transforms(
51
+ %{Sir George Young MP, said\r\n> "I welcome the positive public response to the e-petitions site, which is important way of building a bridge between people and Parliament.”\r\n## The special relationship} =>
52
+ %{Sir George Young MP, said\r\n> I welcome the positive public response to the e-petitions site, which is important way of building a bridge between people and Parliament.\r\n## The special relationship}
53
+ )
54
+ end
55
+
56
+ test "no space in front" do
57
+ assert_remover_transforms(
58
+ %{>"As we continue with the redundancy process we will ensure we retain the capabilities that our armed forces will require to meet the challenges of the future. The redundancy programme will not impact adversely on the current operations in Afghanistan, where our armed forces continue to fight so bravely on this country's behalf."} =>
59
+ %{> As we continue with the redundancy process we will ensure we retain the capabilities that our armed forces will require to meet the challenges of the future. The redundancy programme will not impact adversely on the current operations in Afghanistan, where our armed forces continue to fight so bravely on this country's behalf.}
60
+ )
61
+ end
62
+
63
+ test "remove double double quotes" do
64
+ assert_remover_transforms(
65
+ %{We heard it said:\n\n> ""Today the coalition is remedying those deficiencies by putting in place a new fast track process where the people's elected representatives have responsibility for the final decisions about Britain's future instead of unelected commissioners.""} =>
66
+ %{We heard it said:\n\n> Today the coalition is remedying those deficiencies by putting in place a new fast track process where the people's elected representatives have responsibility for the final decisions about Britain's future instead of unelected commissioners.}
67
+ )
68
+ assert_remover_transforms(
69
+ %{> ""Today the coalition is remedying those deficiencies by putting in place a new fast track process where the people's elected representatives have responsibility for the final decisions about Britain's future instead of unelected commissioners.} =>
70
+ %{> Today the coalition is remedying those deficiencies by putting in place a new fast track process where the people's elected representatives have responsibility for the final decisions about Britain's future instead of unelected commissioners.}
71
+ )
72
+ end
73
+
74
+ test "removes quotes correctly from multi-line blockquotes" do
75
+ assert_remover_transforms(
76
+ %{> "Here is a block quote using 2 lines and two of the arrows.\n> I am not sure how this will render. I think it will mash them together."} =>
77
+ %{> Here is a block quote using 2 lines and two of the arrows.\n> I am not sure how this will render. I think it will mash them together.}
78
+ )
79
+ end
80
+
81
+ test "preserves multiline blockquotes with plain newlines quotes" do
82
+ assert_remover_transforms(
83
+ %{> "line 1\n> \n> "line 2\n> \n> "line 3"} =>
84
+ %{> line 1\n> \n> line 2\n> \n> line 3}
85
+ )
86
+ end
87
+
88
+ test "preserve newlines when there's a blockquote with additional text after" do
89
+ assert_leaves_untouched(%{> \n> blah})
90
+ end
91
+ end
@@ -0,0 +1,112 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'test_helper'
4
+ require 'ostruct'
5
+
6
+ class GovspeakContactsTest < Minitest::Test
7
+
8
+ def build_contact(attrs={})
9
+ OpenStruct.new(
10
+ has_postal_address?: attrs.fetch(:has_postal_address?, true),
11
+ id: attrs.fetch(:id, 123456),
12
+ content_id: attrs.fetch(:content_id, "4f3383e4-48a2-4461-a41d-f85ea8b89ba0"),
13
+ title: attrs.fetch(:title, "Government Digital Service"),
14
+ recipient: attrs.fetch(:recipient, ""),
15
+ street_address: attrs.fetch(:street_address, "125 Kingsway"),
16
+ postal_code: attrs.fetch(:postal_code, "WC2B 6NH"),
17
+ locality: attrs.fetch(:locality, "Holborn"),
18
+ region: attrs.fetch(:region, "London"),
19
+ country_code: attrs.fetch(:country_code, "gb"),
20
+ email: attrs.fetch(:email, "people@digital.cabinet-office.gov.uk"),
21
+ contact_form_url: attrs.fetch(:contact_form_url, ""),
22
+ contact_numbers: attrs.fetch(:contact_numbers,
23
+ [OpenStruct.new(label: "helpdesk", number: "+4412345 67890")]),
24
+ comments: attrs.fetch(:comments, ""),
25
+ worldwide_organisation_path: attrs.fetch(:worldwide_organisation_path, nil),
26
+ )
27
+ end
28
+
29
+ def compress_html(html)
30
+ html.gsub(/[\n\r]+[\s]*/,'')
31
+ end
32
+
33
+ test "contact is rendered when present in options[:contacts]" do
34
+ contact = build_contact
35
+ govspeak = "[Contact:4f3383e4-48a2-4461-a41d-f85ea8b89ba0]"
36
+
37
+ rendered = Govspeak::Document.new(govspeak, { contacts: [contact] }).to_html
38
+ expected_html_output = %{
39
+ <div id="contact_123456" class="contact postal-address">
40
+ <div class="content">
41
+ <h3>Government Digital Service</h3>
42
+ <div class="vcard contact-inner">
43
+ <p class="adr">
44
+ <span class="street-address">125 Kingsway</span><br>
45
+ <span class="locality">Holborn</span><br>
46
+ <span class="region">London</span><br>
47
+ <span class="postal-code">WC2B 6NH</span>
48
+ </p>
49
+ <div class="email-url-number">
50
+ <p class="email">
51
+ <span class="type">Email</span>
52
+ <a href="mailto:people@digital.cabinet-office.gov.uk" class="email">people@digital.cabinet-office.gov.uk</a>
53
+ </p>
54
+ <p class="tel">
55
+ <span class="type">helpdesk</span>
56
+ +4412345 67890
57
+ </p>
58
+ </div>
59
+ </div>
60
+ </div>
61
+ </div>
62
+ }
63
+
64
+ assert_equal(compress_html(expected_html_output), compress_html(rendered))
65
+ end
66
+
67
+ test "no contact is rendered when contact not present in options[:contacts]" do
68
+ contact = build_contact(content_id: "19f06142-1b4a-47ce-b257-964badd0a5e2")
69
+ govspeak = "[Contact:4f3383e4-48a2-4461-a41d-f85ea8b89ba0]"
70
+ rendered = Govspeak::Document.new(govspeak, { contacts: [contact]}).to_html
71
+ assert_match("", rendered)
72
+ end
73
+
74
+ test "no contact is rendered when no contacts are supplied" do
75
+ rendered = Govspeak::Document.new("[Contact:4f3383e4-48a2-4461-a41d-f85ea8b89ba0]").to_html
76
+ assert_match("", rendered)
77
+ end
78
+
79
+ test "contact with no postal address omits the address info" do
80
+ contact = build_contact(has_postal_address?: false)
81
+ govspeak = "[Contact:4f3383e4-48a2-4461-a41d-f85ea8b89ba0]"
82
+ rendered = Govspeak::Document.new(govspeak, { contacts: [contact] }).to_html
83
+ expected_html_output = %{
84
+ <div id="contact_123456" class="contact">
85
+ <div class="content">
86
+ <h3>Government Digital Service</h3>
87
+ <div class="vcard contact-inner">
88
+ <div class="email-url-number">
89
+ <p class="email">
90
+ <span class="type">Email</span>
91
+ <a href="mailto:people@digital.cabinet-office.gov.uk" class="email">people@digital.cabinet-office.gov.uk</a>
92
+ </p>
93
+ <p class="tel">
94
+ <span class="type">helpdesk</span>
95
+ +4412345 67890
96
+ </p>
97
+ </div>
98
+ </div>
99
+ </div>
100
+ </div>
101
+ }
102
+ assert_equal(compress_html(expected_html_output), compress_html(rendered))
103
+ end
104
+
105
+ test "worldwide office contact renders worldwide organisation link" do
106
+ contact = build_contact(worldwide_organisation_path: "/government/world/organisations/british-antarctic-territory")
107
+ govspeak = "[Contact:4f3383e4-48a2-4461-a41d-f85ea8b89ba0]"
108
+ rendered = Govspeak::Document.new(govspeak, { contacts: [contact] }).to_html
109
+ organisation_link = %Q(<a href="/government/world/organisations/british-antarctic-territory">Access and opening times</a>)
110
+ assert_match(organisation_link, rendered)
111
+ end
112
+ end
@@ -18,11 +18,6 @@ class GovspeakTest < Minitest::Test
18
18
  assert_equal "<p><em>this is markdown</em></p>\n", rendered
19
19
  end
20
20
 
21
- test "simple block extension" do
22
- rendered = Govspeak::Document.new("this \n{::reverse}\n*is*\n{:/reverse}\n markdown").to_html
23
- assert_equal "<p>this</p>\n\n<p><em>si</em></p>\n\n<p>markdown</p>\n", rendered
24
- end
25
-
26
21
  test "highlight-answer block extension" do
27
22
  rendered = Govspeak::Document.new("this \n{::highlight-answer}Lead in to *BIG TEXT*\n{:/highlight-answer}").to_html
28
23
  assert_equal %Q{<p>this</p>\n\n<div class="highlight-answer">\n<p>Lead in to <em>BIG TEXT</em></p>\n</div>\n}, rendered
@@ -106,7 +101,29 @@ Testcase Cliffs
106
101
  Teston
107
102
  0123 456 7890 $A }
108
103
  doc = Govspeak::Document.new(input)
109
- assert_equal %{\n<div class="address"><div class="adr org fn"><p>\n123 Test Street<br />Testcase Cliffs<br />Teston<br />0123 456 7890 \n</p></div></div>\n}, doc.to_html
104
+ assert_equal %{\n<div class="address"><div class="adr org fn"><p>\n123 Test Street<br>Testcase Cliffs<br>Teston<br>0123 456 7890 \n</p></div></div>\n}, doc.to_html
105
+ end
106
+
107
+ test "should convert barchart" do
108
+ input = <<-END
109
+ |col|
110
+ |---|
111
+ |val|
112
+ {barchart}
113
+ END
114
+ html = Govspeak::Document.new(input).to_html
115
+ assert_equal %{<table class=\"js-barchart-table mc-auto-outdent\">\n <thead>\n <tr>\n <th>col</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <td>val</td>\n </tr>\n </tbody>\n</table>\n}, html
116
+ end
117
+
118
+ test "should convert barchart with stacked compact and negative" do
119
+ input = <<-END
120
+ |col|
121
+ |---|
122
+ |val|
123
+ {barchart stacked compact negative}
124
+ END
125
+ html = Govspeak::Document.new(input).to_html
126
+ assert_equal %{<table class=\"js-barchart-table mc-stacked compact mc-negative mc-auto-outdent\">\n <thead>\n <tr>\n <th>col</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <td>val</td>\n </tr>\n </tbody>\n</table>\n}, html
110
127
  end
111
128
 
112
129
  test "address div is separated from paragraph text by a couple of line-breaks" do
@@ -119,7 +136,7 @@ Testcase Cliffs
119
136
  Teston
120
137
  0123 456 7890 $A}
121
138
  doc = Govspeak::Document.new(input)
122
- assert_equal %{<p>Paragraph1</p>\n\n<div class="address"><div class="adr org fn"><p>\n123 Test Street<br />Testcase Cliffs<br />Teston<br />0123 456 7890 \n</p></div></div>\n}, doc.to_html
139
+ assert_equal %{<p>Paragraph1</p>\n\n<div class="address"><div class="adr org fn"><p>\n123 Test Street<br>Testcase Cliffs<br>Teston<br>0123 456 7890 \n</p></div></div>\n}, doc.to_html
123
140
  end
124
141
 
125
142
  test_given_govspeak("^ I am very informational ^") do
@@ -156,7 +173,8 @@ Teston
156
173
 
157
174
  test_given_govspeak "@ I am very important @" do
158
175
  assert_html_output %{
159
- <div role="note" aria-label="Important" class="advisory"><p><strong>I am very important</strong></p>
176
+ <div role="note" aria-label="Important" class="advisory">
177
+ <p><strong>I am very important</strong></p>
160
178
  </div>}
161
179
  assert_text_output "I am very important"
162
180
  end
@@ -168,7 +186,8 @@ Teston
168
186
  assert_html_output %{
169
187
  <p>The following is very important</p>
170
188
 
171
- <div role="note" aria-label="Important" class="advisory"><p><strong>I am very important</strong></p>
189
+ <div role="note" aria-label="Important" class="advisory">
190
+ <p><strong>I am very important</strong></p>
172
191
  </div>}
173
192
  assert_text_output "The following is very important I am very important"
174
193
  end
@@ -212,12 +231,12 @@ Teston
212
231
  end
213
232
 
214
233
  test_given_govspeak "This is a [link](http://www.gov.uk) isn't it?" do
215
- assert_html_output '<p>This is a <a href="http://www.gov.uk">link</a> isn&rsquo;t it?</p>'
234
+ assert_html_output '<p>This is a <a href="http://www.gov.uk">link</a> isnt it?</p>'
216
235
  assert_text_output "This is a link isn’t it?"
217
236
  end
218
237
 
219
238
  test_given_govspeak "This is a [link with an at sign in it](http://www.gov.uk/@dg/@this) isn't it?" do
220
- assert_html_output '<p>This is a <a href="http://www.gov.uk/@dg/@this">link with an at sign in it</a> isn&rsquo;t it?</p>'
239
+ assert_html_output '<p>This is a <a href="http://www.gov.uk/@dg/@this">link with an at sign in it</a> isnt it?</p>'
221
240
  assert_text_output "This is a link with an at sign in it isn’t it?"
222
241
  end
223
242
 
@@ -281,7 +300,7 @@ Teston
281
300
  end
282
301
 
283
302
  test_given_govspeak "![image with external url](http://www.example.com/image.jpg)" do
284
- assert_html_output '<p><img src="http://www.example.com/image.jpg" alt="image with external url" /></p>'
303
+ assert_html_output '<p><img src="http://www.example.com/image.jpg" alt="image with external url"></p>'
285
304
  end
286
305
 
287
306
  test "should be able to override default 'document_domains' option" do
@@ -299,9 +318,9 @@ Teston
299
318
  refute html.include?('rel="external"'), "should not automatically add rel external attribute"
300
319
  end
301
320
 
302
- test "should be able to override default 'entity output' option" do
303
- html = Govspeak::Document.new("&yen;", entity_output: :numeric).to_html
304
- assert html.include?("&#165;")
321
+ test "should not be able to override default 'entity output' option" do
322
+ html = Govspeak::Document.new("&gt;", entity_output: :numeric).to_html
323
+ assert html.include?("&gt;")
305
324
  end
306
325
 
307
326
  test "should assume a link with an invalid uri is internal" do
@@ -364,7 +383,7 @@ Teston
364
383
  $A" do
365
384
  assert_html_output %{
366
385
  <div class="address"><div class="adr org fn"><p>
367
- street<br />road<br />
386
+ street<br>road<br>
368
387
  </p></div></div>}
369
388
  assert_text_output "street road"
370
389
  end
@@ -444,11 +463,14 @@ $CTA
444
463
  " do
445
464
  assert_html_output %{
446
465
  <ol class="steps">
447
- <li><p>zippy</p>
466
+ <li>
467
+ <p>zippy</p>
448
468
  </li>
449
- <li><p>bungle</p>
469
+ <li>
470
+ <p>bungle</p>
450
471
  </li>
451
- <li><p>george</p>
472
+ <li>
473
+ <p>george</p>
452
474
  </li>
453
475
  </ol>}
454
476
  assert_text_output "zippy bungle george"
@@ -468,9 +490,11 @@ $CTA
468
490
  </ul>
469
491
 
470
492
  <ol class="steps">
471
- <li><p>step</p>
493
+ <li>
494
+ <p>step</p>
472
495
  </li>
473
- <li><p>list</p>
496
+ <li>
497
+ <p>list</p>
474
498
  </li>
475
499
  </ol>}
476
500
  assert_text_output "unordered list step list"
@@ -591,7 +615,8 @@ $CTA
591
615
  assert_html_output '
592
616
  <div class="devolved-content scotland">
593
617
  <p class="devolved-header">This section applies to Scotland</p>
594
- <div class="devolved-body"><p>I am very devolved
618
+ <div class="devolved-body">
619
+ <p>I am very devolved
595
620
  and very scottish</p>
596
621
  </div>
597
622
  </div>
@@ -600,7 +625,8 @@ $CTA
600
625
 
601
626
  test_given_govspeak "@ Message with [a link](http://foo.bar/)@" do
602
627
  assert_html_output %{
603
- <div role="note" aria-label="Important" class="advisory"><p><strong>Message with <a rel="external" href="http://foo.bar/">a link</a></strong></p>
628
+ <div role="note" aria-label="Important" class="advisory">
629
+ <p><strong>Message with <a rel="external" href="http://foo.bar/">a link</a></strong></p>
604
630
  </div>
605
631
  }
606
632
  end
@@ -610,19 +636,19 @@ $CTA
610
636
  given_govspeak "!!1", images do
611
637
  assert_html_output %Q{
612
638
  <figure class="image embedded">
613
- <div class="img"><img alt="my alt" src="http://example.com/image.jpg" /></div>
639
+ <div class="img"><img alt="my alt" src="http://example.com/image.jpg"></div>
614
640
  </figure>
615
- }
616
- end
641
+ }
617
642
  end
643
+ end
618
644
 
619
- test "alt text of referenced images is escaped" do
620
- images = [OpenStruct.new(alt_text: %Q{my alt '&"<>}, url: "http://example.com/image.jpg")]
621
- given_govspeak "!!1", images do
622
- assert_html_output %Q{
623
- <figure class="image embedded">
624
- <div class="img"><img alt="my alt &apos;&amp;&quot;&lt;&gt;" src="http://example.com/image.jpg" /></div>
625
- </figure>
645
+ test "alt text of referenced images is escaped" do
646
+ images = [OpenStruct.new(alt_text: %Q{my alt '&"<>}, url: "http://example.com/image.jpg")]
647
+ given_govspeak "!!1", images do
648
+ assert_html_output %Q{
649
+ <figure class="image embedded">
650
+ <div class="img"><img alt="my alt '&amp;&quot;&lt;&gt;" src="http://example.com/image.jpg"></div>
651
+ </figure>
626
652
  }
627
653
  end
628
654
  end
@@ -639,7 +665,7 @@ $CTA
639
665
  given_govspeak "!!1", images do
640
666
  assert_html_output %Q{
641
667
  <figure class="image embedded">
642
- <div class="img"><img alt="my alt" src="http://example.com/image.jpg" /></div>
668
+ <div class="img"><img alt="my alt" src="http://example.com/image.jpg"></div>
643
669
  <figcaption>My Caption &amp; so on</figcaption>
644
670
  </figure>
645
671
  }
@@ -651,7 +677,7 @@ $CTA
651
677
  given_govspeak "!!1", images do
652
678
  assert_html_output %Q{
653
679
  <figure class="image embedded">
654
- <div class="img"><img alt="my alt" src="http://example.com/image.jpg" /></div>
680
+ <div class="img"><img alt="my alt" src="http://example.com/image.jpg"></div>
655
681
  </figure>
656
682
  }
657
683
  end
@@ -810,4 +836,111 @@ $PriorityList:1
810
836
  |
811
837
  end
812
838
  end
839
+
840
+ test "should remove quotes surrounding a blockquote" do
841
+ govspeak = %Q{
842
+ He said:
843
+
844
+ > "I'm not sure what you mean!"
845
+
846
+ Or so we thought.}
847
+
848
+ given_govspeak(govspeak) do
849
+ assert_html_output %|
850
+ <p>He said:</p>
851
+
852
+ <blockquote>
853
+ <p class="last-child">I’m not sure what you mean!</p>
854
+ </blockquote>
855
+
856
+ <p>Or so we thought.</p>
857
+ |
858
+ end
859
+ end
860
+
861
+ test "should add class to last paragraph of blockquote" do
862
+ govspeak = "
863
+ > first line
864
+ >
865
+ > last line"
866
+
867
+ given_govspeak(govspeak) do
868
+ assert_html_output %|
869
+ <blockquote>
870
+ <p>first line</p>
871
+
872
+ <p class="last-child">last line</p>
873
+ </blockquote>
874
+ |
875
+ end
876
+ end
877
+
878
+ test "inline attachment" do
879
+ attachment = OpenStruct.new(
880
+ content_id: "2b4d92f3-f8cd-4284-aaaa-25b3a640d26c",
881
+ id: 456,
882
+ )
883
+ govspeak = "[embed:attachments:inline:2b4d92f3-f8cd-4284-aaaa-25b3a640d26c]"
884
+ rendered = Govspeak::Document.new(govspeak, {attachments: attachment}).to_html
885
+ assert_match(/<span id=\"attachment_456\" class=\"attachment-inline\">/, rendered)
886
+ end
887
+
888
+ test "attachment" do
889
+ attachment = OpenStruct.new(
890
+ url: "www.test.com",
891
+ content_id: "2b4d92f3-f8cd-4284-aaaa-25b3a640d26c",
892
+ id: 123,
893
+ opendocument?: true,
894
+ order_url: "www.test.com",
895
+ price: 12.3,
896
+ csv?: true,
897
+ unnumbered_command_paper?: true,
898
+ isbn: 'isbn-123',
899
+ )
900
+ govspeak = "[embed:attachments:2b4d92f3-f8cd-4284-aaaa-25b3a640d26c]"
901
+ rendered = Govspeak::Document.new(govspeak, {attachments: attachment}).to_html
902
+ assert_match(/<section class=\"attachment embedded\">/, rendered)
903
+ assert_match(/<div class=\"attachment-thumb\">/, rendered)
904
+ assert_match(/attachment-123-accessibility-help/, rendered)
905
+ assert_match(/If you use assistive technology/, rendered)
906
+ assert_match(/<p class=\"opendocument-help\">/, rendered)
907
+ assert_match(/<span class=\"price\">£12.30/, rendered)
908
+ assert_match(/<span class=\"preview\">/, rendered)
909
+ assert_match(/<span class=\"unnumbered-paper\">/, rendered)
910
+ assert_match(/<span class=\"references\">/, rendered)
911
+ end
912
+
913
+ test "attachment that isn't provided" do
914
+ govspeak = "[embed:attachments:906ac8b7-850d-45c6-98e0-9525c680f891]"
915
+ rendered = Govspeak::Document.new(govspeak).to_html
916
+ assert_match("", rendered)
917
+ end
918
+
919
+ test "embedded link with link provided" do
920
+ link = OpenStruct.new(
921
+ content_id: "5572fee5-f38f-4641-8ffa-64fed9230ad4",
922
+ url: "https://www.example.com/",
923
+ title: "Example website"
924
+ )
925
+ govspeak = "[embed:link:5572fee5-f38f-4641-8ffa-64fed9230ad4]"
926
+ rendered = Govspeak::Document.new(govspeak, {links: link}).to_html
927
+ expected = %r{<a href="https://www.example.com/">Example website</a>}
928
+ assert_match(expected, rendered)
929
+ end
930
+
931
+ test "embedded link with link not provided" do
932
+ link = OpenStruct.new(
933
+ content_id: "e510f1c1-4862-4333-889c-8d3acd443fbf",
934
+ title: "Example website",
935
+ )
936
+ govspeak = "[embed:link:e510f1c1-4862-4333-889c-8d3acd443fbf]"
937
+ rendered = Govspeak::Document.new(govspeak, {links: link}).to_html
938
+ assert_match("Example website", rendered)
939
+ end
940
+
941
+ test "embedded link without link object" do
942
+ govspeak = "[embed:link:0726637c-8c66-47ad-834a-d815cbf51e0e]"
943
+ rendered = Govspeak::Document.new(govspeak).to_html
944
+ assert_match("", rendered)
945
+ end
813
946
  end