premailer 1.7.1 → 1.7.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,233 @@
1
+ # encoding: UTF-8
2
+ require File.expand_path(File.dirname(__FILE__)) + '/helper'
3
+
4
+ # Random tests for specific issues.
5
+ #
6
+ # The test suite will be cleaned up at some point soon.
7
+ class TestMisc < Test::Unit::TestCase
8
+
9
+ # in response to http://github.com/alexdunae/premailer/issues#issue/4
10
+ #
11
+ # NB: 2010-11-16 -- after reverting to Hpricot this test can no longer pass.
12
+ # It's too much of an edge case to get any dev time.
13
+ def test_parsing_extra_quotes
14
+ io = StringIO.new('<p></p>
15
+ <h3 "id="WAR"><a name="WAR"></a>Writes and Resources</h3>
16
+ <table></table>')
17
+ premailer = Premailer.new(io, :adapter => :nokogiri)
18
+ assert_match /<h3>[\s]*<a name="WAR">[\s]*<\/a>[\s]*Writes and Resources[\s]*<\/h3>/i, premailer.to_inline_css
19
+ end
20
+
21
+ def test_styles_in_the_body
22
+ html = <<END_HTML
23
+ <html>
24
+ <body>
25
+ <style type="text/css"> p { color: red; } </style>
26
+ <p>Test</p>
27
+ </body>
28
+ </html>
29
+ END_HTML
30
+
31
+ premailer = Premailer.new(html, :with_html_string => true)
32
+ premailer.to_inline_css
33
+
34
+ assert_match /color\: red/i, premailer.processed_doc.at('p')['style']
35
+ end
36
+
37
+ def test_commented_out_styles_in_the_body
38
+ html = <<END_HTML
39
+ <html>
40
+ <body>
41
+ <style type="text/css"> <!-- p { color: red; } --> </style>
42
+ <p>Test</p>
43
+ </body>
44
+ </html>
45
+ END_HTML
46
+
47
+ premailer = Premailer.new(html, :with_html_string => true)
48
+ premailer.to_inline_css
49
+
50
+ assert_match /color\: red/i, premailer.processed_doc.at('p')['style']
51
+ end
52
+
53
+ def test_not_applying_styles_to_the_head
54
+ html = <<END_HTML
55
+ <html>
56
+ <head>
57
+ <title>Title</title>
58
+ <style type="text/css"> * { color: red; } </style>
59
+ </head>
60
+ <body>
61
+ <p><a>Test</a></p>
62
+ </body>
63
+ </html>
64
+ END_HTML
65
+
66
+ [:nokogiri, :hpricot].each do |adapter|
67
+ premailer = Premailer.new(html, :with_html_string => true, :adapter => adapter)
68
+ premailer.to_inline_css
69
+
70
+ h = premailer.processed_doc.at('head')
71
+ assert_nil h['style']
72
+
73
+ t = premailer.processed_doc.at('title')
74
+ assert_nil t['style']
75
+ end
76
+ end
77
+
78
+ def test_multiple_identical_ids
79
+ html = <<-END_HTML
80
+ <html>
81
+ <head>
82
+ <style type="text/css"> #the_id { color: red; } </style>
83
+ </head>
84
+ <body>
85
+ <p id="the_id">Test</p>
86
+ <p id="the_id">Test</p>
87
+ </body>
88
+ </html>
89
+ END_HTML
90
+
91
+ premailer = Premailer.new(html, :with_html_string => true)
92
+ premailer.to_inline_css
93
+ premailer.processed_doc.search('p').each do |el|
94
+ assert_match /red/i, el['style']
95
+ end
96
+ end
97
+
98
+ def test_preserving_styles
99
+ html = <<END_HTML
100
+ <html>
101
+ <head>
102
+ <link rel="stylesheet" href="#"/>
103
+ <style type="text/css"> a:hover { color: red; } </style>
104
+ </head>
105
+ <body>
106
+ <p><a>Test</a></p>
107
+ </body>
108
+ </html>
109
+ END_HTML
110
+ [:nokogiri, :hpricot].each do |adapter|
111
+ premailer = Premailer.new(html, :with_html_string => true, :preserve_styles => true, :adapter => adapter)
112
+ premailer.to_inline_css
113
+ assert_equal 1, premailer.processed_doc.search('head link').length
114
+ assert_equal 1, premailer.processed_doc.search('head style').length
115
+
116
+ premailer = Premailer.new(html, :with_html_string => true, :preserve_styles => false, :adapter => adapter)
117
+ premailer.to_inline_css
118
+ assert_nil premailer.processed_doc.at('head link')
119
+
120
+ # should be preserved as unmergeable
121
+ assert_match /red !important/i, premailer.processed_doc.at('body style').inner_html
122
+ end
123
+ end
124
+
125
+ def test_unmergable_rules
126
+ html = <<END_HTML
127
+ <html> <head> <style type="text/css"> a { color:blue; } a:hover { color: red; } </style> </head>
128
+ <p><a>Test</a></p>
129
+ </body> </html>
130
+ END_HTML
131
+
132
+ premailer = Premailer.new(html, :with_html_string => true, :verbose => true)
133
+ premailer.to_inline_css
134
+ assert_match /a\:hover[\s]*\{[\s]*color\:[\s]*red[\s]*!important;[\s]*\}/i, premailer.processed_doc.at('body style').inner_html
135
+ end
136
+
137
+ def test_unmergable_rules_with_no_body
138
+ html = <<END_HTML
139
+ <html>
140
+ <style type="text/css"> a:hover { color: red; } </style>
141
+ <p><a>Test</a></p>
142
+ </html>
143
+ END_HTML
144
+
145
+ premailer = Premailer.new(html, :with_html_string => true)
146
+ assert_nothing_raised do
147
+ premailer.to_inline_css
148
+ end
149
+ assert_match /red !important/i, premailer.processed_doc.at('style').inner_html
150
+ end
151
+
152
+ # in response to https://github.com/alexdunae/premailer/issues#issue/7
153
+ def test_ignoring_link_pseudo_selectors
154
+ html = <<END_HTML
155
+ <html>
156
+ <style type="text/css"> td a:link.top_links { color: red; } </style>
157
+ <body>
158
+ <td><a class="top_links">Test</a></td>
159
+ </body>
160
+ </html>
161
+ END_HTML
162
+
163
+ premailer = Premailer.new(html, :with_html_string => true)
164
+ assert_nothing_raised do
165
+ premailer.to_inline_css
166
+ end
167
+ assert_match /color: red/, premailer.processed_doc.at('a').attributes['style'].to_s
168
+ end
169
+
170
+ # in response to https://github.com/alexdunae/premailer/issues#issue/7
171
+ def test_parsing_bad_markup_around_tables
172
+ html = <<END_HTML
173
+ <html>
174
+ <style type="text/css">
175
+ .style3 { font-size: xx-large; }
176
+ .style5 { background-color: #000080; }
177
+ </style>
178
+ <tr>
179
+ <td valign="top" class="style3">
180
+ <!-- MSCellType="ContentHead" -->
181
+ <strong>PROMOCION CURSOS PRESENCIALES</strong></td>
182
+ <strong>
183
+ <td valign="top" style="height: 125px" class="style5">
184
+ <!-- MSCellType="DecArea" -->
185
+ <img alt="" src="../../images/CertisegGold.GIF" width="608" height="87" /></td>
186
+ </tr>
187
+ END_HTML
188
+
189
+ premailer = Premailer.new(html, :with_html_string => true)
190
+ premailer.to_inline_css
191
+ assert_match /font-size: xx-large/, premailer.processed_doc.search('.style3').first.attributes['style'].to_s
192
+ assert_match /background-color: #000080/, premailer.processed_doc.search('.style5').first.attributes['style'].to_s
193
+ end
194
+
195
+ # in response to https://github.com/alexdunae/premailer/issues/56
196
+ def test_inline_important
197
+ html = <<END_HTML
198
+ <html>
199
+ <style type="text/css">
200
+ p { color: red !important; }
201
+ </style>
202
+ <body>
203
+ <p style='color: green !important;'>test</p></div>
204
+ </body>
205
+ </html>
206
+ END_HTML
207
+
208
+ premailer = Premailer.new(html, :with_html_string => true, :adapter => :nokogiri)
209
+ premailer.to_inline_css
210
+ assert_equal 'color: green !important;', premailer.processed_doc.search('p').first.attributes['style'].to_s
211
+ end
212
+
213
+ # in response to https://github.com/alexdunae/premailer/issues/28
214
+ def test_handling_shorthand_auto_properties
215
+ html = <<END_HTML
216
+ <html>
217
+ <style type="text/css">
218
+ #page { margin: 0; margin-left: auto; margin-right: auto; }
219
+ p { border: 1px solid black; border-right: none; }
220
+
221
+ </style>
222
+ <body>
223
+ <div id='page'><p>test</p></div>
224
+ </body>
225
+ </html>
226
+ END_HTML
227
+
228
+ premailer = Premailer.new(html, :with_html_string => true)
229
+ premailer.to_inline_css
230
+ assert_match /margin: 0 auto;/, premailer.processed_doc.search('#page').first.attributes['style'].to_s
231
+ assert_match /border-style: solid none solid solid;/, premailer.processed_doc.search('p').first.attributes['style'].to_s
232
+ end
233
+ end
@@ -0,0 +1,257 @@
1
+ # encoding: UTF-8
2
+ require File.expand_path(File.dirname(__FILE__)) + '/helper'
3
+
4
+ class TestPremailer < Test::Unit::TestCase
5
+ include WEBrick
6
+
7
+ def setup
8
+ # from http://nullref.se/blog/2006/5/17/testing-with-webrick
9
+ @uri_base = "http://localhost:12000"
10
+ www_root = File.expand_path(File.dirname(__FILE__)) + '/files/'
11
+
12
+ @server_thread = Thread.new do
13
+ s = WEBrick::HTTPServer.new(:Port => 12000, :DocumentRoot => www_root, :Logger => Log.new(nil, BasicLog::ERROR), :AccessLog => [])
14
+ port = s.config[:Port]
15
+ begin
16
+ s.start
17
+ ensure
18
+ s.shutdown
19
+ end
20
+ end
21
+ end
22
+
23
+ def test_special_characters_nokogiri
24
+ html = '<p>cédille c&eacute; & garçon gar&#231;on à &agrave; &nbsp; &amp; &copy;</p>'
25
+ premailer = Premailer.new(html, :with_html_string => true, :adapter => :nokogiri)
26
+ premailer.to_inline_css
27
+ assert_equal 'c&eacute;dille c&eacute; &amp; gar&ccedil;on gar&ccedil;on &agrave; &agrave; &nbsp; &amp; &copy;', premailer.processed_doc.at('p').inner_html
28
+ end
29
+
30
+ def test_special_characters_nokogiri_remote
31
+ remote_setup('chars.html', :adapter => :nokogiri)
32
+ @premailer.to_inline_css
33
+ assert_equal 'c&eacute;dille c&eacute; &amp; gar&ccedil;on gar&ccedil;on &agrave; &agrave; &nbsp; &amp; &copy;', @premailer.processed_doc.at('p').inner_html
34
+ end
35
+
36
+ #def test_cyrillic_nokogiri_remote
37
+ # if RUBY_VERSION =~ /1.9/
38
+ # remote_setup('iso-8859-5.html', :adapter => :nokogiri) #, :encoding => 'iso-8859-5')
39
+ # @premailer.to_inline_css
40
+ # assert_equal Encoding.find('ISO-8859-5'), @premailer.processed_doc.at('p').inner_html.encoding
41
+ # end
42
+ #end
43
+
44
+ # TODO: this passes when run from rake but not when run from:
45
+ # ruby -Itest test/test_premailer.rb -n test_special_characters_hpricot
46
+ def test_special_characters_hpricot
47
+ html = '<p>cédille c&eacute; & garçon gar&#231;on à &agrave; &nbsp; &amp;</p>'
48
+ premailer = Premailer.new(html, :with_html_string => true, :adapter => :hpricot)
49
+ premailer.to_inline_css
50
+ assert_equal 'c&eacute;dille c&eacute; &amp; gar&ccedil;on gar&ccedil;on &agrave; &agrave; &nbsp; &amp;', premailer.processed_doc.at('p').inner_html
51
+ end
52
+
53
+
54
+ def test_detecting_html
55
+ [:nokogiri, :hpricot].each do |adapter|
56
+ remote_setup('base.html', :adapter => adapter)
57
+ assert !@premailer.is_xhtml?
58
+ end
59
+ end
60
+
61
+ def test_detecting_xhtml
62
+ [:nokogiri, :hpricot].each do |adapter|
63
+ remote_setup('xhtml.html', :adapter => adapter)
64
+ assert @premailer.is_xhtml?
65
+ end
66
+ end
67
+
68
+ def test_self_closing_xhtml_tags
69
+ [:nokogiri, :hpricot].each do |adapter|
70
+ remote_setup('xhtml.html', :adapter => adapter)
71
+ assert_match /<br[\s]*\/>/, @premailer.to_s
72
+ assert_match /<br[\s]*\/>/, @premailer.to_inline_css
73
+ end
74
+ end
75
+
76
+ def test_non_self_closing_html_tags
77
+ [:nokogiri, :hpricot].each do |adapter|
78
+ remote_setup('html4.html', :adapter => adapter)
79
+ assert_match /<br>/, @premailer.to_s
80
+ assert_match /<br>/, @premailer.to_inline_css
81
+ end
82
+ end
83
+
84
+ def test_mailtos_with_query_strings
85
+ html = <<END_HTML
86
+ <html>
87
+ <a href="mailto:info@example.com?subject=Programmübersicht&amp;body=Lorem ipsum dolor sit amet.">Test</a>
88
+ </html>
89
+ END_HTML
90
+
91
+ qs = 'testing=123'
92
+
93
+ [:nokogiri, :hpricot].each do |adapter|
94
+ premailer = Premailer.new(html, :with_html_string => true, :link_query_string => qs, :adapter => adapter)
95
+ premailer.to_inline_css
96
+ assert_no_match /testing=123/, premailer.processed_doc.search('a').first.attributes['href'].to_s
97
+ end
98
+ end
99
+
100
+ def test_escaping_strings
101
+ local_setup
102
+
103
+ str = %q{url("/images/test.png");}
104
+ assert_equal("url(\'/images/test.png\');", Premailer.escape_string(str))
105
+ end
106
+
107
+ def test_importing_local_css
108
+ [:nokogiri, :hpricot].each do |adapter|
109
+ local_setup('base.html', :adapter => adapter)
110
+
111
+ # noimport.css (print stylesheet) sets body { background } to red
112
+ assert_no_match /red/, @doc.at('body').attributes['style'].to_s
113
+
114
+ # import.css sets .hide to { display: none }
115
+ assert_match /display: none/, @doc.at('#hide01').attributes['style'].to_s
116
+ end
117
+ end
118
+
119
+ def test_importing_remote_css
120
+ [:nokogiri, :hpricot].each do |adapter|
121
+ remote_setup('base.html', :adapter => adapter)
122
+
123
+ # noimport.css (print stylesheet) sets body { background } to red
124
+ assert_no_match /red/, @doc.at('body')['style']
125
+
126
+ # import.css sets .hide to { display: none }
127
+ assert_match /display: none/, @doc.at('#hide01')['style']
128
+ end
129
+ end
130
+
131
+ def test_importing_css_as_string
132
+ files_base = File.expand_path(File.dirname(__FILE__)) + '/files/'
133
+
134
+ css_string = IO.read(File.join(files_base, 'import.css'))
135
+
136
+ [:nokogiri, :hpricot].each do |adapter|
137
+ premailer = Premailer.new(File.join(files_base, 'no_css.html'), {:css_string => css_string, :adapter => adapter})
138
+ premailer.to_inline_css
139
+ @doc = premailer.processed_doc
140
+
141
+ # import.css sets .hide to { display: none }
142
+ assert_match /display: none/, @doc.at('#hide01')['style']
143
+ end
144
+ end
145
+
146
+ def test_local_remote_check
147
+ assert Premailer.local_data?( StringIO.new('a') )
148
+ assert Premailer.local_data?( '/path/' )
149
+ assert !Premailer.local_data?( 'http://example.com/path/' )
150
+
151
+ # the old way is deprecated but should still work
152
+ premailer = Premailer.new( StringIO.new('a') )
153
+ assert premailer.local_uri?( '/path/' )
154
+ end
155
+
156
+ def test_initialize_can_accept_io_object
157
+ [:nokogiri, :hpricot].each do |adapter|
158
+ io = StringIO.new('hi mom')
159
+ premailer = Premailer.new(io, :adapter => adapter)
160
+ assert_match /hi mom/, premailer.to_inline_css
161
+ end
162
+ end
163
+
164
+ def test_initialize_can_accept_html_string
165
+ [:nokogiri, :hpricot].each do |adapter|
166
+ premailer = Premailer.new('<p>test</p>', :with_html_string => true, :adapter => adapter)
167
+ assert_match /test/, premailer.to_inline_css
168
+ end
169
+ end
170
+
171
+ def test_remove_ids
172
+ html = <<END_HTML
173
+ <html> <head> <style type="text/css"> #remove { color:blue; } </style> </head>
174
+ <body>
175
+ <p id="remove"><a href="#keep">Test</a></p>
176
+ <p id="keep">Test</p>
177
+ </body> </html>
178
+ END_HTML
179
+
180
+ [:nokogiri, :hpricot].each do |adapter|
181
+ pm = Premailer.new(html, :with_html_string => true, :remove_ids => true, :adapter => adapter)
182
+ pm.to_inline_css
183
+ doc = pm.processed_doc
184
+ assert_nil doc.at('#remove')
185
+ assert_nil doc.at('#keep')
186
+ hashed_id = doc.at('a')['href'][1..-1]
187
+ assert_not_nil doc.at("\##{hashed_id}")
188
+ end
189
+ end
190
+
191
+ def test_carriage_returns_as_entities
192
+ html = <<-html
193
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
194
+ <html>
195
+ <body>\n\r<p>test</p>\n\r<p>test</p>
196
+ </body></html>
197
+ html
198
+
199
+ [:nokogiri, :hpricot].each do |adapter|
200
+ pm = Premailer.new(html, :with_html_string => true, :adapter => adapter)
201
+ assert_match /\r/, pm.to_inline_css
202
+ end
203
+ end
204
+
205
+
206
+ def test_advanced_selectors
207
+ remote_setup('base.html', :adapter => :nokogiri)
208
+ assert_match /italic/, @doc.at('h2 + h3')['style']
209
+ assert_match /italic/, @doc.at('p[attr~=quote]')['style']
210
+ assert_match /italic/, @doc.at('ul li:first-of-type')['style']
211
+
212
+ remote_setup('base.html', :adapter => :hpricot)
213
+ assert_match /italic/, @doc.at('p[@attr~="quote"]')['style']
214
+ assert_match /italic/, @doc.at('ul li:first-of-type')['style']
215
+ end
216
+
217
+ def test_premailer_related_attributes
218
+ html = <<END_HTML
219
+ <html> <head> <style>table { -premailer-width: 500; } td { -premailer-height: 20}; </style>
220
+ <body>
221
+ <table> <tr> <td> Test </td> </tr> </table>
222
+ </body> </html>
223
+ END_HTML
224
+
225
+ [:nokogiri, :hpricot].each do |adapter|
226
+ pm = Premailer.new(html, :with_html_string => true, :adapter => adapter)
227
+ pm.to_inline_css
228
+ doc = pm.processed_doc
229
+ assert_equal '500', doc.at('table')['width']
230
+ assert_equal '20', doc.at('td')['height']
231
+ end
232
+ end
233
+
234
+
235
+ protected
236
+ def local_setup(f = 'base.html', opts = {})
237
+ base_file = File.expand_path(File.dirname(__FILE__)) + '/files/' + f
238
+ premailer = Premailer.new(base_file, opts)
239
+ premailer.to_inline_css
240
+ @doc = premailer.processed_doc
241
+ end
242
+
243
+ def remote_setup(f = 'base.html', opts = {})
244
+ # increment the port number for testing multiple adapters
245
+ @premailer = Premailer.new(@uri_base + "/#{f}", opts)
246
+ @premailer.to_inline_css
247
+ @doc = @premailer.processed_doc
248
+ end
249
+
250
+ def teardown
251
+ if @server_thread
252
+ @server_thread.kill
253
+ @server_thread.join(5)
254
+ @server_thread = nil
255
+ end
256
+ end
257
+ end