roadie 3.5.1 → 5.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +46 -0
- data/.rubocop.yml +5 -0
- data/.solargraph.yml +16 -0
- data/Changelog.md +35 -4
- data/Gemfile +7 -2
- data/README.md +14 -14
- data/Rakefile +4 -3
- data/lib/roadie/asset_provider.rb +5 -1
- data/lib/roadie/asset_scanner.rb +8 -6
- data/lib/roadie/cached_provider.rb +3 -0
- data/lib/roadie/deduplicator.rb +3 -0
- data/lib/roadie/document.rb +24 -17
- data/lib/roadie/errors.rb +22 -16
- data/lib/roadie/filesystem_provider.rb +15 -3
- data/lib/roadie/inliner.rb +51 -19
- data/lib/roadie/markup_improver.rb +24 -31
- data/lib/roadie/net_http_provider.rb +27 -12
- data/lib/roadie/null_provider.rb +20 -5
- data/lib/roadie/null_url_rewriter.rb +11 -3
- data/lib/roadie/path_rewriter_provider.rb +6 -1
- data/lib/roadie/provider_list.rb +17 -11
- data/lib/roadie/rspec/asset_provider.rb +6 -1
- data/lib/roadie/rspec/cache_store.rb +2 -0
- data/lib/roadie/rspec.rb +4 -2
- data/lib/roadie/selector.rb +18 -5
- data/lib/roadie/style_attribute_builder.rb +4 -1
- data/lib/roadie/style_block.rb +5 -3
- data/lib/roadie/style_property.rb +5 -2
- data/lib/roadie/stylesheet.rb +4 -13
- data/lib/roadie/url_generator.rb +26 -8
- data/lib/roadie/url_rewriter.rb +12 -9
- data/lib/roadie/utils.rb +3 -1
- data/lib/roadie/version.rb +1 -1
- data/lib/roadie.rb +25 -23
- data/roadie.gemspec +23 -23
- data/spec/hash_as_cache_store_spec.rb +3 -1
- data/spec/integration_spec.rb +75 -44
- data/spec/lib/roadie/asset_scanner_spec.rb +11 -5
- data/spec/lib/roadie/cached_provider_spec.rb +6 -4
- data/spec/lib/roadie/css_not_found_spec.rb +10 -5
- data/spec/lib/roadie/deduplicator_spec.rb +5 -3
- data/spec/lib/roadie/document_spec.rb +57 -28
- data/spec/lib/roadie/filesystem_provider_spec.rb +10 -11
- data/spec/lib/roadie/inliner_spec.rb +42 -45
- data/spec/lib/roadie/markup_improver_spec.rb +19 -26
- data/spec/lib/roadie/net_http_provider_spec.rb +16 -14
- data/spec/lib/roadie/null_provider_spec.rb +4 -3
- data/spec/lib/roadie/null_url_rewriter_spec.rb +4 -3
- data/spec/lib/roadie/path_rewriter_provider_spec.rb +6 -4
- data/spec/lib/roadie/provider_list_spec.rb +27 -22
- data/spec/lib/roadie/selector_spec.rb +7 -5
- data/spec/lib/roadie/style_attribute_builder_spec.rb +7 -5
- data/spec/lib/roadie/style_block_spec.rb +3 -2
- data/spec/lib/roadie/style_property_spec.rb +10 -8
- data/spec/lib/roadie/stylesheet_spec.rb +4 -21
- data/spec/lib/roadie/test_provider_spec.rb +6 -4
- data/spec/lib/roadie/url_generator_spec.rb +3 -2
- data/spec/lib/roadie/url_rewriter_spec.rb +10 -7
- data/spec/lib/roadie/utils_spec.rb +2 -0
- data/spec/shared_examples/asset_provider.rb +2 -0
- data/spec/shared_examples/url_rewriter.rb +5 -3
- data/spec/spec_helper.rb +10 -8
- data/spec/support/have_attribute_matcher.rb +3 -2
- data/spec/support/have_node_matcher.rb +5 -3
- data/spec/support/have_selector_matcher.rb +4 -3
- data/spec/support/have_styling_matcher.rb +12 -11
- data/spec/support/have_xpath_matcher.rb +4 -3
- data/spec/support/test_provider.rb +2 -0
- metadata +24 -8
- data/.travis.yml +0 -22
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "spec_helper"
|
2
4
|
|
3
5
|
module Roadie
|
@@ -7,13 +9,13 @@ module Roadie
|
|
7
9
|
["a", "1"],
|
8
10
|
["b", "2"],
|
9
11
|
["a", "3"],
|
10
|
-
["a", "1"]
|
12
|
+
["a", "1"]
|
11
13
|
]
|
12
14
|
|
13
15
|
expect(Deduplicator.apply(input)).to eq [
|
14
16
|
["b", "2"],
|
15
17
|
["a", "3"],
|
16
|
-
["a", "1"]
|
18
|
+
["a", "1"]
|
17
19
|
]
|
18
20
|
end
|
19
21
|
|
@@ -21,7 +23,7 @@ module Roadie
|
|
21
23
|
input = [
|
22
24
|
["a", "1"],
|
23
25
|
["a", "3"],
|
24
|
-
["a", "2"]
|
26
|
+
["a", "2"]
|
25
27
|
]
|
26
28
|
|
27
29
|
expect(Deduplicator.apply(input)).to eq input
|
@@ -1,5 +1,6 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
3
4
|
|
4
5
|
module Roadie
|
5
6
|
describe Document do
|
@@ -16,6 +17,16 @@ module Roadie
|
|
16
17
|
expect(document.url_options).to eq({host: "foo.bar"})
|
17
18
|
end
|
18
19
|
|
20
|
+
it "has an accessor for serialization options" do
|
21
|
+
serialization_options = Nokogiri::XML::Node::SaveOptions::FORMAT |
|
22
|
+
Nokogiri::XML::Node::SaveOptions::NO_EMPTY_TAGS
|
23
|
+
document.serialization_options = serialization_options
|
24
|
+
expect(document.serialization_options).to eq(serialization_options)
|
25
|
+
|
26
|
+
document.serialization_options = nil
|
27
|
+
expect(document.serialization_options).to eq(0)
|
28
|
+
end
|
29
|
+
|
19
30
|
it "has a setting for keeping uninlinable styles" do
|
20
31
|
expect(document.keep_uninlinable_css).to be true
|
21
32
|
document.keep_uninlinable_css = false
|
@@ -69,6 +80,9 @@ module Roadie
|
|
69
80
|
|
70
81
|
document.mode = :html
|
71
82
|
expect(document.mode).to eq(:html)
|
83
|
+
|
84
|
+
document.mode = :xml
|
85
|
+
expect(document.mode).to eq(:xml)
|
72
86
|
end
|
73
87
|
|
74
88
|
it "does not allow unknown modes" do
|
@@ -90,8 +104,8 @@ module Roadie
|
|
90
104
|
describe "transforming" do
|
91
105
|
it "runs the before and after callbacks" do
|
92
106
|
document = Document.new "<body></body>"
|
93
|
-
before = ->{}
|
94
|
-
after = ->{}
|
107
|
+
before = -> {}
|
108
|
+
after = -> {}
|
95
109
|
document.before_transformation = before
|
96
110
|
document.after_transformation = after
|
97
111
|
|
@@ -102,21 +116,6 @@ module Roadie
|
|
102
116
|
document.transform
|
103
117
|
end
|
104
118
|
|
105
|
-
# TODO: Remove on next major version.
|
106
|
-
it "works on callables that don't expect more than one argument" do
|
107
|
-
document = Document.new "<body></body>"
|
108
|
-
document.before_transformation = ->(first) { }
|
109
|
-
document.after_transformation = ->(first = nil) { }
|
110
|
-
|
111
|
-
expect { document.transform }.to_not raise_error
|
112
|
-
|
113
|
-
# It still supplies the second argument, if possible.
|
114
|
-
document.after_transformation = ->(first, second = nil) {
|
115
|
-
raise "Oops" unless second
|
116
|
-
}
|
117
|
-
expect { document.transform }.to_not raise_error
|
118
|
-
end
|
119
|
-
|
120
119
|
context "in HTML mode" do
|
121
120
|
it "does not escape curly braces" do
|
122
121
|
document = Document.new "<body><a href='https://google.com/{{hello}}'>Hello</a></body>"
|
@@ -125,26 +124,41 @@ module Roadie
|
|
125
124
|
expect(document.transform).to include("{{hello}}")
|
126
125
|
end
|
127
126
|
end
|
127
|
+
|
128
|
+
context "in XML mode" do
|
129
|
+
it "doesn't replace empty tags with self-closed ones" do
|
130
|
+
document = Document.new "<img src='https://google.com/image.png'></img>"
|
131
|
+
document.mode = :xml
|
132
|
+
|
133
|
+
expect(document.transform_partial).to end_with("</img>")
|
134
|
+
end
|
135
|
+
|
136
|
+
it "does not escape curly braces" do
|
137
|
+
document = Document.new "<a href='https://google.com/{{hello}}'>Hello</a>"
|
138
|
+
document.mode = :xml
|
139
|
+
expect(document.transform_partial).to include("{{hello}}")
|
140
|
+
end
|
141
|
+
end
|
128
142
|
end
|
129
143
|
|
130
144
|
describe "partial transforming" do
|
131
145
|
it "runs the before and after callbacks" do
|
132
146
|
document = Document.new "<p></p>"
|
133
|
-
before = ->{}
|
134
|
-
after = ->{}
|
147
|
+
before = -> {}
|
148
|
+
after = -> {}
|
135
149
|
document.before_transformation = before
|
136
150
|
document.after_transformation = after
|
137
151
|
|
138
152
|
expect(before).to receive(:call).with(
|
139
153
|
instance_of(Nokogiri::HTML::DocumentFragment),
|
140
|
-
document
|
154
|
+
document
|
141
155
|
).ordered
|
142
156
|
|
143
157
|
expect(Inliner).to receive(:new).ordered.and_return double.as_null_object
|
144
158
|
|
145
159
|
expect(after).to receive(:call).with(
|
146
160
|
instance_of(Nokogiri::HTML::DocumentFragment),
|
147
|
-
document
|
161
|
+
document
|
148
162
|
).ordered
|
149
163
|
|
150
164
|
document.transform_partial
|
@@ -158,6 +172,21 @@ module Roadie
|
|
158
172
|
expect(document.transform_partial).to include("{{hello}}")
|
159
173
|
end
|
160
174
|
end
|
175
|
+
|
176
|
+
context "in XML mode" do
|
177
|
+
it "doesn't replace empty tags with self-closed ones" do
|
178
|
+
document = Document.new "<img src='https://google.com/image.png'></img>"
|
179
|
+
document.mode = :xml
|
180
|
+
|
181
|
+
expect(document.transform_partial).to end_with("</img>")
|
182
|
+
end
|
183
|
+
|
184
|
+
it "does not escape curly braces" do
|
185
|
+
document = Document.new "<a href='https://google.com/{{hello}}'>Hello</a>"
|
186
|
+
document.mode = :xml
|
187
|
+
expect(document.transform_partial).to include("{{hello}}")
|
188
|
+
end
|
189
|
+
end
|
161
190
|
end
|
162
191
|
end
|
163
192
|
|
@@ -178,11 +207,11 @@ module Roadie
|
|
178
207
|
|
179
208
|
result = Nokogiri::HTML.parse document.transform
|
180
209
|
|
181
|
-
expect(result).to have_selector(
|
182
|
-
expect(result.at_css(
|
210
|
+
expect(result).to have_selector("html > head > title")
|
211
|
+
expect(result.at_css("title").text).to eq("Greetings")
|
183
212
|
|
184
|
-
expect(result).to have_selector(
|
185
|
-
paragraph = result.at_css(
|
213
|
+
expect(result).to have_selector("html > body > p")
|
214
|
+
paragraph = result.at_css("p")
|
186
215
|
expect(paragraph.text).to eq("Hello, world!")
|
187
216
|
expect(paragraph.to_xml).to eq('<p style="color:green">Hello, world!</p>')
|
188
217
|
end
|
@@ -201,7 +230,7 @@ module Roadie
|
|
201
230
|
HTML
|
202
231
|
|
203
232
|
document.asset_providers = TestProvider.new({
|
204
|
-
"/sample.css" => "p { color: red; text-align: right; }"
|
233
|
+
"/sample.css" => "p { color: red; text-align: right; }"
|
205
234
|
})
|
206
235
|
|
207
236
|
document.add_css "p { color: green; text-size: 2em; }"
|
@@ -1,7 +1,8 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
require "roadie/rspec"
|
5
|
+
require "shared_examples/asset_provider"
|
5
6
|
|
6
7
|
module Roadie
|
7
8
|
describe FilesystemProvider do
|
@@ -62,13 +63,11 @@ module Roadie
|
|
62
63
|
end
|
63
64
|
|
64
65
|
it "shows that the query string is ignored inside raised errors" do
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
expect(error.to_s).to include("/foo.css?query-string")
|
71
|
-
end
|
66
|
+
provider.find_stylesheet!("/foo.css?query-string")
|
67
|
+
fail "No error was raised"
|
68
|
+
rescue CssNotFound => error
|
69
|
+
expect(error.css_name).to eq("foo.css")
|
70
|
+
expect(error.to_s).to include("/foo.css?query-string")
|
72
71
|
end
|
73
72
|
end
|
74
73
|
end
|
@@ -1,10 +1,13 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
3
4
|
|
4
5
|
module Roadie
|
5
6
|
describe Inliner do
|
6
|
-
before { @stylesheet = ""
|
7
|
-
def use_css(css)
|
7
|
+
before { @stylesheet = "" }
|
8
|
+
def use_css(css)
|
9
|
+
@stylesheet = Stylesheet.new("example", css)
|
10
|
+
end
|
8
11
|
|
9
12
|
def rendering(html, stylesheet = @stylesheet)
|
10
13
|
dom = Nokogiri::HTML.parse html
|
@@ -14,17 +17,17 @@ module Roadie
|
|
14
17
|
|
15
18
|
describe "inlining styles" do
|
16
19
|
it "inlines simple attributes" do
|
17
|
-
use_css
|
18
|
-
expect(rendering(
|
20
|
+
use_css "p { color: green }"
|
21
|
+
expect(rendering("<p></p>")).to have_styling("color" => "green")
|
19
22
|
end
|
20
23
|
|
21
24
|
it "keeps multiple versions of the same property to support progressive enhancement" do
|
22
25
|
# https://github.com/premailer/css_parser/issues/44
|
23
26
|
pending "css_parser issue #44"
|
24
27
|
|
25
|
-
use_css
|
26
|
-
expect(rendering(
|
27
|
-
[[
|
28
|
+
use_css "p { color: #eee; color: rgba(255, 255, 255, 0.9); }"
|
29
|
+
expect(rendering("<p></p>")).to have_styling(
|
30
|
+
[["color", "green"], ["color", "rgba(255, 255, 255, 0.9)"]]
|
28
31
|
)
|
29
32
|
end
|
30
33
|
|
@@ -35,35 +38,35 @@ module Roadie
|
|
35
38
|
.positive { color: green; }
|
36
39
|
'
|
37
40
|
expect(rendering('<p class="message positive"></p>')).to have_styling(
|
38
|
-
[[
|
41
|
+
[["color", "blue"], ["color", "green"]]
|
39
42
|
)
|
40
43
|
end
|
41
44
|
|
42
45
|
it "inlines browser-prefixed attributes" do
|
43
|
-
use_css
|
44
|
-
expect(rendering(
|
46
|
+
use_css "p { -vendor-color: green }"
|
47
|
+
expect(rendering("<p></p>")).to have_styling("-vendor-color" => "green")
|
45
48
|
end
|
46
49
|
|
47
50
|
it "inlines CSS3 attributes" do
|
48
|
-
use_css
|
49
|
-
expect(rendering(
|
51
|
+
use_css "p { border-radius: 2px; }"
|
52
|
+
expect(rendering("<p></p>")).to have_styling("border-radius" => "2px")
|
50
53
|
end
|
51
54
|
|
52
55
|
it "keeps the order of the styles that are inlined" do
|
53
|
-
use_css
|
54
|
-
expect(rendering(
|
56
|
+
use_css "h1 { padding: 2px; margin: 5px; }"
|
57
|
+
expect(rendering("<h1></h1>")).to have_styling([["padding", "2px"], ["margin", "5px"]])
|
55
58
|
end
|
56
59
|
|
57
60
|
it "combines multiple selectors into one" do
|
58
61
|
use_css 'p { color: green; }
|
59
62
|
.tip { float: right; }'
|
60
|
-
expect(rendering('<p class="tip"></p>')).to have_styling([[
|
63
|
+
expect(rendering('<p class="tip"></p>')).to have_styling([["color", "green"], ["float", "right"]])
|
61
64
|
end
|
62
65
|
|
63
66
|
it "uses the attributes with the highest specificity when conflicts arises" do
|
64
67
|
use_css ".safe { color: green; }
|
65
68
|
p { color: red; }"
|
66
|
-
expect(rendering('<p class="safe"></p>')).to have_styling([[
|
69
|
+
expect(rendering('<p class="safe"></p>')).to have_styling([["color", "red"], ["color", "green"]])
|
67
70
|
end
|
68
71
|
|
69
72
|
it "sorts styles by specificity order" do
|
@@ -81,10 +84,10 @@ module Roadie
|
|
81
84
|
end
|
82
85
|
|
83
86
|
it "supports multiple selectors for the same rules" do
|
84
|
-
use_css
|
85
|
-
rendering(
|
86
|
-
expect(document).to have_styling(
|
87
|
-
expect(document).to have_styling(
|
87
|
+
use_css "p, a { color: green; }"
|
88
|
+
rendering("<p></p><a></a>").tap do |document|
|
89
|
+
expect(document).to have_styling("color" => "green").at_selector("p")
|
90
|
+
expect(document).to have_styling("color" => "green").at_selector("a")
|
88
91
|
end
|
89
92
|
end
|
90
93
|
|
@@ -92,22 +95,22 @@ module Roadie
|
|
92
95
|
use_css "a { text-decoration: underline !important; }
|
93
96
|
a.hard-to-spot { text-decoration: none; }"
|
94
97
|
expect(rendering('<a class="hard-to-spot"></a>')).to have_styling([
|
95
|
-
[
|
98
|
+
["text-decoration", "none"], ["text-decoration", "underline !important"]
|
96
99
|
])
|
97
100
|
end
|
98
101
|
|
99
102
|
it "combines with already present inline styles" do
|
100
103
|
use_css "p { color: green }"
|
101
|
-
expect(rendering('<p style="font-size: 1.1em"></p>')).to have_styling([[
|
104
|
+
expect(rendering('<p style="font-size: 1.1em"></p>')).to have_styling([["color", "green"], ["font-size", "1.1em"]])
|
102
105
|
end
|
103
106
|
|
104
107
|
it "does not override inline styles" do
|
105
108
|
use_css "p { text-transform: uppercase; color: red }"
|
106
109
|
# The two color properties are kept to make css fallbacks work correctly
|
107
110
|
expect(rendering('<p style="color: green"></p>')).to have_styling([
|
108
|
-
[
|
109
|
-
[
|
110
|
-
[
|
111
|
+
["text-transform", "uppercase"],
|
112
|
+
["color", "red"],
|
113
|
+
["color", "green"]
|
111
114
|
])
|
112
115
|
end
|
113
116
|
|
@@ -122,7 +125,7 @@ module Roadie
|
|
122
125
|
|
123
126
|
p.active { width: 100%; }
|
124
127
|
"
|
125
|
-
expect(rendering('<p class="active"></p>')).to have_styling(
|
128
|
+
expect(rendering('<p class="active"></p>')).to have_styling("width" => "100%")
|
126
129
|
end
|
127
130
|
|
128
131
|
it "does not crash on any pseudo element selectors" do
|
@@ -130,7 +133,7 @@ module Roadie
|
|
130
133
|
p.some-element { width: 100%; }
|
131
134
|
p::some-element { color: red; }
|
132
135
|
"
|
133
|
-
expect(rendering('<p class="some-element"></p>')).to have_styling(
|
136
|
+
expect(rendering('<p class="some-element"></p>')).to have_styling("width" => "100%")
|
134
137
|
end
|
135
138
|
|
136
139
|
it "warns on selectors that crash Nokogiri" do
|
@@ -139,7 +142,7 @@ module Roadie
|
|
139
142
|
stylesheet = Stylesheet.new "foo.css", "p[%^=foo] { color: red; }"
|
140
143
|
inliner = Inliner.new([stylesheet], dom)
|
141
144
|
expect(Utils).to receive(:warn).with(
|
142
|
-
%
|
145
|
+
%(Cannot inline "p[%^=foo]" from "foo.css" stylesheet. If this is valid CSS, please report a bug.)
|
143
146
|
)
|
144
147
|
inliner.inline
|
145
148
|
end
|
@@ -151,8 +154,8 @@ module Roadie
|
|
151
154
|
"
|
152
155
|
result = rendering("<p></p> <p></p>")
|
153
156
|
|
154
|
-
expect(result).to have_styling([[
|
155
|
-
expect(result).to have_styling([[
|
157
|
+
expect(result).to have_styling([["color", "red"]]).at_selector("p:first")
|
158
|
+
expect(result).to have_styling([["color", "red"], ["color", "green"]]).at_selector("p:last")
|
156
159
|
end
|
157
160
|
|
158
161
|
context "with uninlinable selectors" do
|
@@ -161,7 +164,7 @@ module Roadie
|
|
161
164
|
end
|
162
165
|
|
163
166
|
it "puts them in a new <style> element in the <head>" do
|
164
|
-
use_css
|
167
|
+
use_css "a:hover { color: red; }"
|
165
168
|
result = rendering("
|
166
169
|
<html>
|
167
170
|
<head></head>
|
@@ -173,7 +176,7 @@ module Roadie
|
|
173
176
|
end
|
174
177
|
|
175
178
|
it "puts them in <head> on unexpected inlining problems" do
|
176
|
-
use_css
|
179
|
+
use_css "p:some-future-thing { color: red; }"
|
177
180
|
result = rendering("
|
178
181
|
<html>
|
179
182
|
<head></head>
|
@@ -197,15 +200,9 @@ module Roadie
|
|
197
200
|
}'
|
198
201
|
|
199
202
|
use_css css
|
200
|
-
result = rendering(
|
203
|
+
result = rendering("<p></p>")
|
201
204
|
|
202
205
|
expect(result).to have_styling([]).at_selector("p")
|
203
|
-
|
204
|
-
# css_parser actually sees an empty @keyframes on JRuby, and nothing
|
205
|
-
# on the others
|
206
|
-
if (style_element = result.at_css("head > style"))
|
207
|
-
expect(style_element.text).to_not include "background-position"
|
208
|
-
end
|
209
206
|
end
|
210
207
|
|
211
208
|
it "ignores them if told not to keep them" do
|
@@ -224,14 +221,14 @@ module Roadie
|
|
224
221
|
end
|
225
222
|
|
226
223
|
it "puts the <style> element at the root when told so" do
|
227
|
-
stylesheet = use_css
|
224
|
+
stylesheet = use_css "a:hover { color: red; }"
|
228
225
|
dom = Nokogiri::HTML.fragment("
|
229
226
|
<a></a>
|
230
227
|
")
|
231
228
|
|
232
229
|
Inliner.new([stylesheet], dom).inline(
|
233
230
|
keep_uninlinable_css: true,
|
234
|
-
keep_uninlinable_in: :root
|
231
|
+
keep_uninlinable_in: :root
|
235
232
|
)
|
236
233
|
|
237
234
|
expect(dom).to have_xpath("./a")
|
@@ -239,7 +236,7 @@ module Roadie
|
|
239
236
|
end
|
240
237
|
|
241
238
|
it "raises error when told to save styles in an unknown place" do
|
242
|
-
stylesheet = use_css
|
239
|
+
stylesheet = use_css "a:hover { color: red; }"
|
243
240
|
dom = Nokogiri::HTML.fragment("
|
244
241
|
<a></a>
|
245
242
|
")
|
@@ -248,7 +245,7 @@ module Roadie
|
|
248
245
|
expect {
|
249
246
|
inliner.inline(
|
250
247
|
keep_uninlinable_css: true,
|
251
|
-
keep_uninlinable_in: :unknown_place
|
248
|
+
keep_uninlinable_in: :unknown_place
|
252
249
|
)
|
253
250
|
}.to raise_error(ArgumentError, /:unknown_place/)
|
254
251
|
end
|
@@ -1,5 +1,6 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
3
4
|
|
4
5
|
module Roadie
|
5
6
|
describe MarkupImprover do
|
@@ -9,22 +10,14 @@ module Roadie
|
|
9
10
|
dom
|
10
11
|
end
|
11
12
|
|
12
|
-
# JRuby up to at least 1.6.0 has a bug where the doctype of a document cannot be changed.
|
13
|
-
# See https://github.com/sparklemotion/nokogiri/issues/984
|
14
|
-
def pending_for_buggy_jruby
|
15
|
-
# No reason to check for version yet since no existing version has a fix.
|
16
|
-
skip "Pending until Nokogiri issue #984 is fixed and released" if defined?(JRuby)
|
17
|
-
end
|
18
|
-
|
19
13
|
describe "automatic doctype" do
|
20
14
|
it "inserts a HTML5 doctype if no doctype is present" do
|
21
|
-
pending_for_buggy_jruby
|
22
15
|
expect(improve("<html></html>").internal_subset.to_xml).to eq("<!DOCTYPE html>")
|
23
16
|
end
|
24
17
|
|
25
18
|
it "does not insert duplicate doctypes" do
|
26
|
-
html = improve(
|
27
|
-
expect(html.scan(
|
19
|
+
html = improve("<!DOCTYPE html><html><body></body></html>").to_html
|
20
|
+
expect(html.scan("DOCTYPE").size).to eq(1)
|
28
21
|
end
|
29
22
|
|
30
23
|
it "leaves other doctypes alone" do
|
@@ -38,35 +31,35 @@ module Roadie
|
|
38
31
|
it "inserts a <html> element as the root" do
|
39
32
|
expect(improve("")).to have_selector("html")
|
40
33
|
expect(improve("<h1>Hey!</h1>")).to have_selector("html h1")
|
41
|
-
expect(improve("<html></html>").css(
|
34
|
+
expect(improve("<html></html>").css("html").size).to eq(1)
|
42
35
|
end
|
43
36
|
|
44
37
|
it "inserts <head> if not present" do
|
45
|
-
expect(improve(
|
46
|
-
expect(improve(
|
47
|
-
expect(improve(
|
48
|
-
expect(improve(
|
38
|
+
expect(improve("<html><body></body></html>")).to have_selector("html > head + body")
|
39
|
+
expect(improve("<html></html>")).to have_selector("html > head")
|
40
|
+
expect(improve("Foo")).to have_selector("html > head")
|
41
|
+
expect(improve("<html><head></head></html>").css("head").size).to eq(1)
|
49
42
|
end
|
50
43
|
|
51
44
|
it "inserts <body> if not present" do
|
52
|
-
expect(improve(
|
53
|
-
expect(improve(
|
54
|
-
expect(improve(
|
45
|
+
expect(improve("<h1>Hey!</h1>")).to have_selector("html > body > h1")
|
46
|
+
expect(improve("<html><h1>Hey!</h1></html>")).to have_selector("html > body > h1")
|
47
|
+
expect(improve("<html><body><h1>Hey!</h1></body></html>").css("body").size).to eq(1)
|
55
48
|
end
|
56
49
|
end
|
57
50
|
|
58
51
|
describe "charset declaration" do
|
59
52
|
it "is inserted if missing" do
|
60
|
-
dom = improve(
|
53
|
+
dom = improve("<html><head></head><body></body></html>")
|
61
54
|
|
62
|
-
expect(dom).to have_selector(
|
63
|
-
meta = dom.at_css(
|
64
|
-
expect(meta[
|
65
|
-
expect(meta[
|
55
|
+
expect(dom).to have_selector("head meta")
|
56
|
+
meta = dom.at_css("head meta")
|
57
|
+
expect(meta["http-equiv"]).to eq("Content-Type")
|
58
|
+
expect(meta["content"]).to eq("text/html; charset=UTF-8")
|
66
59
|
end
|
67
60
|
|
68
61
|
it "is left alone when predefined" do
|
69
|
-
expect(improve(<<-HTML).xpath(
|
62
|
+
expect(improve(<<-HTML).xpath("//meta")).to have(1).item
|
70
63
|
<html>
|
71
64
|
<head>
|
72
65
|
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
|
@@ -1,6 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
require "roadie/rspec"
|
5
|
+
require "shared_examples/asset_provider"
|
4
6
|
|
5
7
|
module Roadie
|
6
8
|
describe NetHttpProvider do
|
@@ -10,7 +12,7 @@ module Roadie
|
|
10
12
|
WebMock.allow_net_connect!
|
11
13
|
end
|
12
14
|
|
13
|
-
url = "http://example.com/style.css"
|
15
|
+
url = "http://example.com/style.css"
|
14
16
|
|
15
17
|
it_behaves_like(
|
16
18
|
"roadie asset provider",
|
@@ -18,13 +20,13 @@ module Roadie
|
|
18
20
|
invalid_name: "http://example.com/red.css"
|
19
21
|
) do
|
20
22
|
before do
|
21
|
-
stub_request(:get, "http://example.com/green.css").and_return(body: "p { color: green; }")
|
23
|
+
stub_request(:get, "http://example.com/green.css").and_return(body: +"p { color: green; }")
|
22
24
|
stub_request(:get, "http://example.com/red.css").and_return(status: 404, body: "Not here!")
|
23
25
|
end
|
24
26
|
end
|
25
27
|
|
26
28
|
it "can download over HTTPS" do
|
27
|
-
stub_request(:get, "https://example.com/style.css").and_return(body: "p { color: green; }")
|
29
|
+
stub_request(:get, "https://example.com/style.css").and_return(body: +"p { color: green; }")
|
28
30
|
expect {
|
29
31
|
NetHttpProvider.new.find_stylesheet!("https://example.com/style.css")
|
30
32
|
}.to_not raise_error
|
@@ -37,7 +39,7 @@ module Roadie
|
|
37
39
|
# asset inlining, but the scheme-less URL implies that there should exist
|
38
40
|
# both a HTTP and a HTTPS endpoint. Let's take the secure one in that
|
39
41
|
# case!
|
40
|
-
stub_request(:get, "https://example.com/style.css").and_return(body: "p { color: green; }")
|
42
|
+
stub_request(:get, "https://example.com/style.css").and_return(body: +"p { color: green; }")
|
41
43
|
expect {
|
42
44
|
NetHttpProvider.new.find_stylesheet!("//example.com/style.css")
|
43
45
|
}.to_not raise_error
|
@@ -48,8 +50,8 @@ module Roadie
|
|
48
50
|
# (US-ASCII). The headers will indicate what charset the client should
|
49
51
|
# use when trying to make sense of these bytes.
|
50
52
|
stub_request(:get, url).and_return(
|
51
|
-
body:
|
52
|
-
headers: {"Content-Type" => "text/css;charset=ISO-8859-1"}
|
53
|
+
body: (+%(p::before { content: "l\xF6ve" })).force_encoding("US-ASCII"),
|
54
|
+
headers: {"Content-Type" => "text/css;charset=ISO-8859-1"}
|
53
55
|
)
|
54
56
|
|
55
57
|
# Seems like CssParser strips out the non-ascii character for some
|
@@ -64,8 +66,8 @@ module Roadie
|
|
64
66
|
|
65
67
|
it "assumes UTF-8 encoding if server headers do not specify a charset" do
|
66
68
|
stub_request(:get, url).and_return(
|
67
|
-
body:
|
68
|
-
headers: {"Content-Type" => "text/css"}
|
69
|
+
body: (+%(p::before { content: "Åh nej" })).force_encoding("US-ASCII"),
|
70
|
+
headers: {"Content-Type" => "text/css"}
|
69
71
|
)
|
70
72
|
|
71
73
|
# Seems like CssParser strips out the non-ascii characters for some
|
@@ -117,10 +119,10 @@ module Roadie
|
|
117
119
|
provider = NetHttpProvider.new(whitelist: ["whitelisted.example.com"])
|
118
120
|
|
119
121
|
whitelisted_url = "http://whitelisted.example.com/style.css"
|
120
|
-
other_url
|
122
|
+
other_url = "http://www.example.com/style.css"
|
121
123
|
|
122
|
-
whitelisted_request = stub_request(:get, whitelisted_url).and_return(body: "x")
|
123
|
-
other_request
|
124
|
+
whitelisted_request = stub_request(:get, whitelisted_url).and_return(body: +"x")
|
125
|
+
other_request = stub_request(:get, other_url).and_return(body: +"x")
|
124
126
|
|
125
127
|
expect(provider.find_stylesheet(other_url)).to be_nil
|
126
128
|
expect {
|