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
data/lib/roadie/url_generator.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "set"
|
2
4
|
|
3
5
|
module Roadie
|
4
6
|
# @api private
|
@@ -21,8 +23,15 @@ module Roadie
|
|
21
23
|
# @option url_options [String] :scheme URL scheme ("http" is default)
|
22
24
|
# @option url_options [String] :protocol alias for :scheme
|
23
25
|
def initialize(url_options)
|
24
|
-
|
25
|
-
|
26
|
+
unless url_options
|
27
|
+
raise ArgumentError, "No URL options were specified"
|
28
|
+
end
|
29
|
+
|
30
|
+
unless url_options[:host]
|
31
|
+
raise ArgumentError,
|
32
|
+
"No :host was specified; options were: #{url_options.inspect}"
|
33
|
+
end
|
34
|
+
|
26
35
|
validate_options url_options
|
27
36
|
|
28
37
|
@url_options = url_options
|
@@ -56,7 +65,7 @@ module Roadie
|
|
56
65
|
# @param [String] base The base which the relative path comes from
|
57
66
|
# @return [String] an absolute URL
|
58
67
|
def generate_url(path, base = "/")
|
59
|
-
return root_uri.to_s if path.nil?
|
68
|
+
return root_uri.to_s if path.nil? || path.empty?
|
60
69
|
return path if path_is_anchor?(path)
|
61
70
|
return add_scheme(path) if path_is_schemeless?(path)
|
62
71
|
return path if Utils.path_is_absolute?(path)
|
@@ -65,13 +74,20 @@ module Roadie
|
|
65
74
|
end
|
66
75
|
|
67
76
|
protected
|
77
|
+
|
68
78
|
attr_reader :root_uri, :scheme
|
69
79
|
|
70
80
|
private
|
81
|
+
|
71
82
|
def build_root_uri
|
72
83
|
path = make_absolute url_options[:path]
|
73
84
|
port = parse_port url_options[:port]
|
74
|
-
URI::Generic.build(
|
85
|
+
URI::Generic.build(
|
86
|
+
scheme: scheme,
|
87
|
+
host: url_options[:host],
|
88
|
+
port: port,
|
89
|
+
path: path
|
90
|
+
)
|
75
91
|
end
|
76
92
|
|
77
93
|
def add_scheme(path)
|
@@ -96,7 +112,7 @@ module Roadie
|
|
96
112
|
|
97
113
|
# Strip :// from any scheme, if present
|
98
114
|
def normalize_scheme(scheme)
|
99
|
-
return
|
115
|
+
return "http" unless scheme
|
100
116
|
scheme.to_s[/^\w+/]
|
101
117
|
end
|
102
118
|
|
@@ -117,7 +133,7 @@ module Roadie
|
|
117
133
|
end
|
118
134
|
|
119
135
|
def path_is_anchor?(path)
|
120
|
-
path.start_with?
|
136
|
+
path.start_with? "#"
|
121
137
|
end
|
122
138
|
|
123
139
|
VALID_OPTIONS = Set[:host, :port, :path, :protocol, :scheme].freeze
|
@@ -125,7 +141,9 @@ module Roadie
|
|
125
141
|
def validate_options(options)
|
126
142
|
keys = Set.new(options.keys)
|
127
143
|
unless keys.subset? VALID_OPTIONS
|
128
|
-
raise ArgumentError,
|
144
|
+
raise ArgumentError,
|
145
|
+
"Passed invalid options: #{(keys - VALID_OPTIONS).to_a}, " \
|
146
|
+
"valid options are: #{VALID_OPTIONS.to_a}"
|
129
147
|
end
|
130
148
|
end
|
131
149
|
end
|
data/lib/roadie/url_rewriter.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Roadie
|
2
4
|
# @api private
|
3
5
|
#
|
@@ -23,9 +25,9 @@ module Roadie
|
|
23
25
|
dom.css(
|
24
26
|
"a[href]:not([data-roadie-ignore]), " \
|
25
27
|
"img[src]:not([data-roadie-ignore]), " \
|
26
|
-
"*[style]:not([data-roadie-ignore])"
|
28
|
+
"*[style]:not([data-roadie-ignore])"
|
27
29
|
).each do |element|
|
28
|
-
transform_element_style element if element.has_attribute?(
|
30
|
+
transform_element_style element if element.has_attribute?("style")
|
29
31
|
transform_element element
|
30
32
|
end
|
31
33
|
nil
|
@@ -35,20 +37,22 @@ module Roadie
|
|
35
37
|
#
|
36
38
|
# This will make all URLs inside url() absolute.
|
37
39
|
#
|
38
|
-
#
|
39
|
-
# the passed string.
|
40
|
+
# Copy of CSS that is mutated is returned, passed string is not mutated.
|
40
41
|
#
|
41
42
|
# @param [String] css the css to mutate
|
42
|
-
# @return [
|
43
|
+
# @return [String] copy of css that is mutated
|
43
44
|
def transform_css(css)
|
44
|
-
css.gsub
|
45
|
+
css.gsub(CSS_URL_REGEXP) do
|
45
46
|
matches = Regexp.last_match
|
46
47
|
"url(#{matches[:quote]}#{generate_url(matches[:url])}#{matches[:quote]})"
|
47
48
|
end
|
48
49
|
end
|
49
50
|
|
50
51
|
private
|
51
|
-
|
52
|
+
|
53
|
+
def generate_url(*args)
|
54
|
+
@generator.generate_url(*args)
|
55
|
+
end
|
52
56
|
|
53
57
|
# Regexp matching all the url() declarations in CSS
|
54
58
|
#
|
@@ -81,8 +85,7 @@ module Roadie
|
|
81
85
|
# We need to use a setter for Nokogiri to detect the string mutation.
|
82
86
|
# If nokogiri used "dumber" data structures, this would all be redundant.
|
83
87
|
css = element["style"]
|
84
|
-
transform_css
|
85
|
-
element["style"] = css
|
88
|
+
element["style"] = transform_css(css)
|
86
89
|
end
|
87
90
|
end
|
88
91
|
end
|
data/lib/roadie/utils.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Roadie
|
2
4
|
module Utils
|
3
5
|
# @api private
|
@@ -8,7 +10,7 @@ module Roadie
|
|
8
10
|
#
|
9
11
|
# URLs that start with double slashes (//css/app.css) are also absolute
|
10
12
|
# in modern browsers, but most email clients do not understand them.
|
11
|
-
return true if
|
13
|
+
return true if %r{^(\w+:|//)}.match?(path)
|
12
14
|
|
13
15
|
begin
|
14
16
|
!URI.parse(path).relative?
|
data/lib/roadie/version.rb
CHANGED
data/lib/roadie.rb
CHANGED
@@ -1,30 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Roadie
|
2
4
|
end
|
3
5
|
|
4
|
-
require
|
5
|
-
require
|
6
|
+
require "roadie/version"
|
7
|
+
require "roadie/errors"
|
6
8
|
|
7
|
-
require
|
8
|
-
require
|
9
|
+
require "roadie/utils"
|
10
|
+
require "roadie/deduplicator"
|
9
11
|
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require
|
14
|
-
require
|
12
|
+
require "roadie/stylesheet"
|
13
|
+
require "roadie/selector"
|
14
|
+
require "roadie/style_property"
|
15
|
+
require "roadie/style_attribute_builder"
|
16
|
+
require "roadie/style_block"
|
15
17
|
|
16
|
-
require
|
17
|
-
require
|
18
|
-
require
|
19
|
-
require
|
20
|
-
require
|
21
|
-
require
|
22
|
-
require
|
18
|
+
require "roadie/asset_provider"
|
19
|
+
require "roadie/provider_list"
|
20
|
+
require "roadie/filesystem_provider"
|
21
|
+
require "roadie/null_provider"
|
22
|
+
require "roadie/net_http_provider"
|
23
|
+
require "roadie/cached_provider"
|
24
|
+
require "roadie/path_rewriter_provider"
|
23
25
|
|
24
|
-
require
|
25
|
-
require
|
26
|
-
require
|
27
|
-
require
|
28
|
-
require
|
29
|
-
require
|
30
|
-
require
|
26
|
+
require "roadie/asset_scanner"
|
27
|
+
require "roadie/markup_improver"
|
28
|
+
require "roadie/url_generator"
|
29
|
+
require "roadie/url_rewriter"
|
30
|
+
require "roadie/null_url_rewriter"
|
31
|
+
require "roadie/inliner"
|
32
|
+
require "roadie/document"
|
data/roadie.gemspec
CHANGED
@@ -1,33 +1,33 @@
|
|
1
1
|
# roadie.gemspec
|
2
|
-
#
|
2
|
+
# frozen_string_literal: true
|
3
3
|
|
4
4
|
$:.push File.expand_path("../lib", __FILE__)
|
5
|
-
require
|
5
|
+
require "roadie/version"
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
|
-
s.name
|
9
|
-
s.version
|
10
|
-
s.platform
|
11
|
-
s.authors
|
12
|
-
s.email
|
13
|
-
s.homepage
|
14
|
-
s.summary
|
15
|
-
s.description =
|
16
|
-
s.license
|
17
|
-
|
18
|
-
s.required_ruby_version = ">=
|
19
|
-
|
20
|
-
s.add_dependency
|
21
|
-
s.add_dependency
|
22
|
-
|
23
|
-
s.add_development_dependency
|
24
|
-
s.add_development_dependency
|
25
|
-
s.add_development_dependency
|
8
|
+
s.name = "roadie"
|
9
|
+
s.version = Roadie::VERSION
|
10
|
+
s.platform = Gem::Platform::RUBY
|
11
|
+
s.authors = ["Magnus Bergmark"]
|
12
|
+
s.email = ["magnus.bergmark@gmail.com"]
|
13
|
+
s.homepage = "http://github.com/Mange/roadie"
|
14
|
+
s.summary = "Making HTML emails comfortable for the Ruby rockstars"
|
15
|
+
s.description = "Roadie tries to make sending HTML emails a little less painful by inlining stylesheets and rewriting relative URLs for you."
|
16
|
+
s.license = "MIT"
|
17
|
+
|
18
|
+
s.required_ruby_version = ">= 2.6"
|
19
|
+
|
20
|
+
s.add_dependency "nokogiri", "~> 1.8"
|
21
|
+
s.add_dependency "css_parser", "~> 1.4"
|
22
|
+
|
23
|
+
s.add_development_dependency "rake"
|
24
|
+
s.add_development_dependency "rspec", "~> 3.0"
|
25
|
+
s.add_development_dependency "rspec-collection_matchers", "~> 1.0"
|
26
|
+
s.add_development_dependency "webmock", "~> 3.0"
|
26
27
|
|
27
28
|
s.extra_rdoc_files = %w[README.md Changelog.md]
|
28
29
|
s.require_paths = %w[lib]
|
29
30
|
|
30
|
-
s.files
|
31
|
-
s.test_files
|
31
|
+
s.files = `git ls-files`.split("\n")
|
32
|
+
s.test_files = `git ls-files -- spec/*`.split("\n")
|
32
33
|
end
|
33
|
-
|
data/spec/integration_spec.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
2
4
|
|
3
5
|
describe "Roadie functionality" do
|
4
6
|
describe "on full documents" do
|
@@ -11,14 +13,7 @@ describe "Roadie functionality" do
|
|
11
13
|
document = Roadie::Document.new(html)
|
12
14
|
result = document.transform
|
13
15
|
|
14
|
-
|
15
|
-
# JRuby has a bug that makes DTD manipulation impossible
|
16
|
-
# See Nokogiri bugs #984 and #985
|
17
|
-
# https://github.com/sparklemotion/nokogiri/issues/984
|
18
|
-
# https://github.com/sparklemotion/nokogiri/issues/985
|
19
|
-
expect(result).to include("<!DOCTYPE html>")
|
20
|
-
end
|
21
|
-
|
16
|
+
expect(result).to include("<!DOCTYPE html>")
|
22
17
|
expect(result).to include("<html>")
|
23
18
|
expect(result).to include("<head>")
|
24
19
|
expect(result).to include("<body>")
|
@@ -45,8 +40,8 @@ describe "Roadie functionality" do
|
|
45
40
|
CSS
|
46
41
|
|
47
42
|
result = parse_html document.transform
|
48
|
-
expect(result).to have_styling(
|
49
|
-
expect(result).to have_styling(
|
43
|
+
expect(result).to have_styling("text-align" => "center").at_selector("h1")
|
44
|
+
expect(result).to have_styling("color" => "red").at_selector("p > em")
|
50
45
|
end
|
51
46
|
|
52
47
|
it "stores styles that cannot be inlined in the <head>" do
|
@@ -110,7 +105,7 @@ describe "Roadie functionality" do
|
|
110
105
|
HTML
|
111
106
|
|
112
107
|
result = parse_html document.transform
|
113
|
-
expect(result).to have_styling(
|
108
|
+
expect(result).to have_styling("font-size" => "200%").at_selector("p > em")
|
114
109
|
end
|
115
110
|
|
116
111
|
it "crashes when stylesheets cannot be found, unless using NullProvider" do
|
@@ -125,7 +120,9 @@ describe "Roadie functionality" do
|
|
125
120
|
</html>
|
126
121
|
HTML
|
127
122
|
|
128
|
-
expect {
|
123
|
+
expect {
|
124
|
+
document.transform
|
125
|
+
}.to raise_error(Roadie::CssNotFound, /does_not_exist\.css/)
|
129
126
|
|
130
127
|
document.asset_providers << Roadie::NullProvider.new
|
131
128
|
expect { document.transform }.to_not raise_error
|
@@ -149,8 +146,8 @@ describe "Roadie functionality" do
|
|
149
146
|
document.external_asset_providers = []
|
150
147
|
|
151
148
|
result = parse_html document.transform
|
152
|
-
expect(result).to have_selector(
|
153
|
-
expect(result).to have_styling([]).at_selector(
|
149
|
+
expect(result).to have_selector("head > link")
|
150
|
+
expect(result).to have_styling([]).at_selector("p > em")
|
154
151
|
end
|
155
152
|
|
156
153
|
it "inlines external css if configured" do
|
@@ -173,8 +170,8 @@ describe "Roadie functionality" do
|
|
173
170
|
)
|
174
171
|
|
175
172
|
result = parse_html document.transform
|
176
|
-
expect(result).to have_styling(
|
177
|
-
expect(result).to_not have_selector(
|
173
|
+
expect(result).to have_styling("font-size" => "200%").at_selector("p > em")
|
174
|
+
expect(result).to_not have_selector("head > link")
|
178
175
|
end
|
179
176
|
|
180
177
|
it "does not inline the same properties several times" do
|
@@ -195,8 +192,8 @@ describe "Roadie functionality" do
|
|
195
192
|
|
196
193
|
result = parse_html document.transform
|
197
194
|
expect(result).to have_styling([
|
198
|
-
[
|
199
|
-
]).at_selector(
|
195
|
+
["color", "red"]
|
196
|
+
]).at_selector("p")
|
200
197
|
end
|
201
198
|
|
202
199
|
it "makes URLs absolute" do
|
@@ -230,7 +227,7 @@ describe "Roadie functionality" do
|
|
230
227
|
).at_selector("body")
|
231
228
|
|
232
229
|
expect(result).to have_styling(
|
233
|
-
"background" =>
|
230
|
+
"background" => "url(https://myapp.com/rails/app/assets/link-abcdef1234567890.png)"
|
234
231
|
).at_selector("a")
|
235
232
|
end
|
236
233
|
|
@@ -322,10 +319,10 @@ describe "Roadie functionality" do
|
|
322
319
|
)
|
323
320
|
|
324
321
|
result = parse_html document.transform
|
325
|
-
expect(result).to have_styling(
|
322
|
+
expect(result).to have_styling("color" => "green").at_selector(".colorful")
|
326
323
|
end
|
327
324
|
|
328
|
-
it
|
325
|
+
it "puts non-inlineable media queries in the head" do
|
329
326
|
document = Roadie::Document.new <<-HTML
|
330
327
|
<html>
|
331
328
|
<head>
|
@@ -351,18 +348,18 @@ describe "Roadie functionality" do
|
|
351
348
|
|
352
349
|
result = parse_html document.transform
|
353
350
|
|
354
|
-
styles = result.at_css(
|
351
|
+
styles = result.at_css("html > head > style").text
|
355
352
|
expected_result = <<-CSS
|
356
353
|
@media screen and (max-width 800px) { .colorful{color:blue} }
|
357
354
|
@media screen, print and (max-width 800px) { .colorful{color:blue} }
|
358
355
|
CSS
|
359
|
-
expected_result = expected_result.gsub(
|
360
|
-
actual_result = styles.gsub(
|
356
|
+
expected_result = expected_result.gsub(/\s+/, " ").strip
|
357
|
+
actual_result = styles.gsub(/\s+/, " ").strip
|
361
358
|
|
362
359
|
expect(actual_result).to eq(expected_result)
|
363
360
|
end
|
364
361
|
|
365
|
-
it
|
362
|
+
it "groups non-inlineable media queries in the head by default" do
|
366
363
|
document = Roadie::Document.new <<-HTML
|
367
364
|
<html>
|
368
365
|
<head>
|
@@ -388,20 +385,52 @@ describe "Roadie functionality" do
|
|
388
385
|
|
389
386
|
result = parse_html document.transform
|
390
387
|
|
391
|
-
styles = result.at_css(
|
388
|
+
styles = result.at_css("html > head > style").text
|
392
389
|
expected_result = <<-CSS
|
393
390
|
@media screen and (max-width 600px) {
|
394
391
|
.colorful{color:red;width:600px}
|
395
392
|
.colorful-2{color:red;width:600px}
|
396
393
|
}
|
397
394
|
CSS
|
398
|
-
expected_result = expected_result.gsub(
|
399
|
-
actual_result = styles.gsub(
|
395
|
+
expected_result = expected_result.gsub(/\s+/, " ").strip
|
396
|
+
actual_result = styles.gsub(/\s+/, " ").strip
|
400
397
|
|
401
398
|
expect(actual_result).to eq(expected_result)
|
402
399
|
end
|
403
400
|
|
404
|
-
|
401
|
+
it "adds XML declaration into XHTML with no serialization options prohibiting it" do
|
402
|
+
document = Roadie::Document.new <<-HTML
|
403
|
+
<html>
|
404
|
+
<head>
|
405
|
+
<title>Greetings</title>
|
406
|
+
</head>
|
407
|
+
</html>
|
408
|
+
HTML
|
409
|
+
|
410
|
+
document.mode = :xhtml
|
411
|
+
document.serialization_options = 0
|
412
|
+
result = document.transform
|
413
|
+
|
414
|
+
expect(result).to match(/\A<\?xml[^>]*?>/i)
|
415
|
+
end
|
416
|
+
|
417
|
+
it "does not add XML declaration into XHTML with serialization options prohibiting it" do
|
418
|
+
document = Roadie::Document.new <<-HTML
|
419
|
+
<html>
|
420
|
+
<head>
|
421
|
+
<title>Greetings</title>
|
422
|
+
</head>
|
423
|
+
</html>
|
424
|
+
HTML
|
425
|
+
|
426
|
+
document.mode = :xhtml
|
427
|
+
document.serialization_options = Nokogiri::XML::Node::SaveOptions::NO_DECLARATION
|
428
|
+
result = document.transform
|
429
|
+
|
430
|
+
expect(result).not_to match(/\A<\?xml[^>]*?>/i)
|
431
|
+
end
|
432
|
+
|
433
|
+
describe "if merge_media_queries is set to false" do
|
405
434
|
it "doesn't group non-inlineable media queries in the head" do
|
406
435
|
document = Roadie::Document.new <<-HTML
|
407
436
|
<html>
|
@@ -430,7 +459,7 @@ describe "Roadie functionality" do
|
|
430
459
|
|
431
460
|
result = parse_html document.transform
|
432
461
|
|
433
|
-
styles = result.at_css(
|
462
|
+
styles = result.at_css("html > head > style").text
|
434
463
|
expected_result = <<-CSS
|
435
464
|
@media screen and (max-width 600px) {
|
436
465
|
.colorful{color:red;width:600px}
|
@@ -439,8 +468,8 @@ describe "Roadie functionality" do
|
|
439
468
|
.colorful-2{color:red;width:600px}
|
440
469
|
}
|
441
470
|
CSS
|
442
|
-
expected_result = expected_result.gsub(
|
443
|
-
actual_result = styles.gsub(
|
471
|
+
expected_result = expected_result.gsub(/\s+/, " ").strip
|
472
|
+
actual_result = styles.gsub(/\s+/, " ").strip
|
444
473
|
|
445
474
|
expect(actual_result).to eq(expected_result)
|
446
475
|
end
|
@@ -472,8 +501,8 @@ describe "Roadie functionality" do
|
|
472
501
|
CSS
|
473
502
|
|
474
503
|
result = parse_html document.transform_partial
|
475
|
-
expect(result).to have_styling(
|
476
|
-
expect(result).to have_styling(
|
504
|
+
expect(result).to have_styling("text-align" => "center").at_selector("h1")
|
505
|
+
expect(result).to have_styling("color" => "red").at_selector("p > em")
|
477
506
|
end
|
478
507
|
|
479
508
|
it "stores styles that cannot be inlined in a new <style> element" do
|
@@ -521,7 +550,7 @@ describe "Roadie functionality" do
|
|
521
550
|
HTML
|
522
551
|
|
523
552
|
result = parse_html document.transform_partial
|
524
|
-
expect(result).to have_styling(
|
553
|
+
expect(result).to have_styling("font-size" => "200%").at_selector("p > em")
|
525
554
|
end
|
526
555
|
|
527
556
|
it "crashes when stylesheets cannot be found, unless using NullProvider" do
|
@@ -529,7 +558,9 @@ describe "Roadie functionality" do
|
|
529
558
|
<link rel="stylesheet" href="/spec/fixtures/does_not_exist.css">
|
530
559
|
HTML
|
531
560
|
|
532
|
-
expect {
|
561
|
+
expect {
|
562
|
+
document.transform_partial
|
563
|
+
}.to raise_error(Roadie::CssNotFound, /does_not_exist\.css/)
|
533
564
|
|
534
565
|
document.asset_providers << Roadie::NullProvider.new
|
535
566
|
expect { document.transform_partial }.to_not raise_error
|
@@ -545,8 +576,8 @@ describe "Roadie functionality" do
|
|
545
576
|
document.external_asset_providers = []
|
546
577
|
|
547
578
|
result = parse_html document.transform_partial
|
548
|
-
expect(result).to have_xpath(
|
549
|
-
expect(result).to have_styling([]).at_selector(
|
579
|
+
expect(result).to have_xpath("./link")
|
580
|
+
expect(result).to have_styling([]).at_selector("p > em")
|
550
581
|
end
|
551
582
|
|
552
583
|
it "inlines external css if configured" do
|
@@ -561,8 +592,8 @@ describe "Roadie functionality" do
|
|
561
592
|
)
|
562
593
|
|
563
594
|
result = parse_html document.transform_partial
|
564
|
-
expect(result).to have_styling(
|
565
|
-
expect(result).to_not have_xpath(
|
595
|
+
expect(result).to have_styling("font-size" => "200%").at_selector("p > em")
|
596
|
+
expect(result).to_not have_xpath("./link")
|
566
597
|
end
|
567
598
|
|
568
599
|
it "does not inline the same properties several times" do
|
@@ -579,8 +610,8 @@ describe "Roadie functionality" do
|
|
579
610
|
|
580
611
|
result = parse_html document.transform_partial
|
581
612
|
expect(result).to have_styling([
|
582
|
-
[
|
583
|
-
]).at_selector(
|
613
|
+
["color", "red"]
|
614
|
+
]).at_selector("p")
|
584
615
|
end
|
585
616
|
|
586
617
|
it "makes URLs absolute" do
|
@@ -613,7 +644,7 @@ describe "Roadie functionality" do
|
|
613
644
|
).at_selector("div")
|
614
645
|
|
615
646
|
expect(result).to have_styling(
|
616
|
-
"background" =>
|
647
|
+
"background" => "url(https://myapp.com/rails/app/assets/link-abcdef1234567890.png)"
|
617
648
|
).at_selector("a")
|
618
649
|
end
|
619
650
|
|
@@ -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 AssetScanner do
|
@@ -7,8 +8,13 @@ module Roadie
|
|
7
8
|
let(:external_provider) { ProviderList.empty }
|
8
9
|
let(:dom) { dom_document "<html></html>" }
|
9
10
|
|
10
|
-
def dom_fragment(html)
|
11
|
-
|
11
|
+
def dom_fragment(html)
|
12
|
+
Nokogiri::HTML.fragment html
|
13
|
+
end
|
14
|
+
|
15
|
+
def dom_document(html)
|
16
|
+
Nokogiri::HTML.parse html
|
17
|
+
end
|
12
18
|
|
13
19
|
it "is initialized with a DOM tree, a normal asset provider set, and an external asset provider set" do
|
14
20
|
scanner = AssetScanner.new dom, normal_provider, external_provider
|
@@ -110,7 +116,7 @@ module Roadie
|
|
110
116
|
expect(scanner.find_css).to eq([])
|
111
117
|
end
|
112
118
|
|
113
|
-
it
|
119
|
+
it "ignores HTML comments and CDATA sections" do
|
114
120
|
# TinyMCE posts invalid CSS. We support that just to be pragmatic.
|
115
121
|
dom = dom_fragment %(<style><![CDATA[
|
116
122
|
<!--
|
@@ -1,11 +1,13 @@
|
|
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 CachedProvider do
|
7
9
|
let(:upstream) { TestProvider.new("good.css" => "body { color: green; }") }
|
8
|
-
let(:cache) {
|
10
|
+
let(:cache) { {} }
|
9
11
|
subject(:provider) { CachedProvider.new(upstream, cache) }
|
10
12
|
|
11
13
|
it_behaves_like "roadie asset provider", valid_name: "good.css", invalid_name: "bad.css"
|
@@ -1,22 +1,27 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
2
4
|
|
3
5
|
module Roadie
|
4
6
|
describe CssNotFound do
|
5
7
|
it "is initialized with a name" do
|
6
|
-
error = CssNotFound.new(
|
7
|
-
expect(error.css_name).to eq(
|
8
|
+
error = CssNotFound.new(css_name: "style.css")
|
9
|
+
expect(error.css_name).to eq("style.css")
|
8
10
|
expect(error.message).to eq('Could not find stylesheet "style.css"')
|
9
11
|
end
|
10
12
|
|
11
13
|
it "can be initialized with an extra message" do
|
12
|
-
|
14
|
+
error = CssNotFound.new(css_name: "file.css", message: "directory is missing")
|
15
|
+
expect(error.message).to eq(
|
13
16
|
'Could not find stylesheet "file.css": directory is missing'
|
14
17
|
)
|
15
18
|
end
|
16
19
|
|
17
20
|
it "shows information about used provider when given" do
|
18
21
|
provider = double("Some cool provider")
|
19
|
-
|
22
|
+
error = CssNotFound.new(css_name: "style.css", provider: provider)
|
23
|
+
|
24
|
+
expect(error.message).to eq(
|
20
25
|
%(Could not find stylesheet "style.css"\nUsed provider:\n#{provider})
|
21
26
|
)
|
22
27
|
end
|