roadie 3.5.1 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 {
|