roadie 3.0.0.pre1 → 3.0.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/.travis.yml +1 -0
- data/Changelog.md +22 -1
- data/Gemfile +0 -4
- data/Guardfile +3 -2
- data/README.md +6 -4
- data/lib/roadie.rb +3 -1
- data/lib/roadie/filesystem_provider.rb +13 -2
- data/lib/roadie/inliner.rb +10 -8
- data/lib/roadie/markup_improver.rb +1 -1
- data/lib/roadie/provider_list.rb +5 -1
- data/lib/roadie/rspec/asset_provider.rb +9 -9
- data/lib/roadie/selector.rb +1 -0
- data/lib/roadie/style_attribute_builder.rb +25 -0
- data/lib/roadie/style_block.rb +0 -1
- data/lib/roadie/upgrade_guide.rb +36 -0
- data/lib/roadie/version.rb +1 -1
- data/roadie.gemspec +2 -1
- data/spec/integration_spec.rb +15 -15
- data/spec/lib/roadie/asset_scanner_spec.rb +27 -27
- data/spec/lib/roadie/css_not_found_spec.rb +4 -3
- data/spec/lib/roadie/document_spec.rb +19 -19
- data/spec/lib/roadie/filesystem_provider_spec.rb +29 -6
- data/spec/lib/roadie/inliner_spec.rb +18 -18
- data/spec/lib/roadie/markup_improver_spec.rb +17 -17
- data/spec/lib/roadie/null_provider_spec.rb +4 -4
- data/spec/lib/roadie/provider_list_spec.rb +23 -15
- data/spec/lib/roadie/selector_spec.rb +16 -13
- data/spec/lib/roadie/style_attribute_builder_spec.rb +29 -0
- data/spec/lib/roadie/style_block_spec.rb +6 -6
- data/spec/lib/roadie/style_property_spec.rb +22 -22
- data/spec/lib/roadie/stylesheet_spec.rb +8 -8
- data/spec/lib/roadie/test_provider_spec.rb +5 -5
- data/spec/lib/roadie/url_generator_spec.rb +21 -20
- data/spec/lib/roadie/url_rewriter_spec.rb +7 -7
- data/spec/shared_examples/asset_provider.rb +4 -4
- data/spec/shared_examples/url_rewriter.rb +6 -6
- data/spec/spec_helper.rb +2 -1
- data/spec/support/have_attribute_matcher.rb +2 -2
- data/spec/support/have_node_matcher.rb +2 -2
- data/spec/support/have_selector_matcher.rb +2 -2
- data/spec/support/have_styling_matcher.rb +7 -5
- metadata +36 -21
- data/lib/roadie/style_properties.rb +0 -29
- data/spec/lib/roadie/style_properties_spec.rb +0 -61
@@ -11,14 +11,14 @@ module Roadie
|
|
11
11
|
|
12
12
|
it "is initialized with a DOM tree and a asset provider set" do
|
13
13
|
scanner = AssetScanner.new dom, provider
|
14
|
-
scanner.dom.
|
15
|
-
scanner.asset_provider.
|
14
|
+
expect(scanner.dom).to eq(dom)
|
15
|
+
expect(scanner.asset_provider).to eq(provider)
|
16
16
|
end
|
17
17
|
|
18
18
|
describe "finding" do
|
19
19
|
it "returns nothing when no stylesheets are referenced" do
|
20
20
|
scanner = AssetScanner.new dom, provider
|
21
|
-
scanner.find_css.
|
21
|
+
expect(scanner.find_css).to eq([])
|
22
22
|
end
|
23
23
|
|
24
24
|
it "finds all embedded stylesheets" do
|
@@ -38,11 +38,11 @@ module Roadie
|
|
38
38
|
|
39
39
|
stylesheets = scanner.find_css
|
40
40
|
|
41
|
-
stylesheets.
|
42
|
-
stylesheets[0].to_s.
|
43
|
-
stylesheets[1].to_s.
|
41
|
+
expect(stylesheets).to have(2).stylesheets
|
42
|
+
expect(stylesheets[0].to_s).to include("green")
|
43
|
+
expect(stylesheets[1].to_s).to include("red")
|
44
44
|
|
45
|
-
stylesheets.first.name.
|
45
|
+
expect(stylesheets.first.name).to eq("(inline)")
|
46
46
|
end
|
47
47
|
|
48
48
|
it "does not find any embedded stylesheets marked for ignoring" do
|
@@ -55,35 +55,35 @@ module Roadie
|
|
55
55
|
</html>
|
56
56
|
HTML
|
57
57
|
scanner = AssetScanner.new dom, provider
|
58
|
-
scanner.find_css.
|
58
|
+
expect(scanner.find_css).to have(1).stylesheet
|
59
59
|
end
|
60
60
|
|
61
61
|
it "finds referenced stylesheets through the provider" do
|
62
62
|
stylesheet = double "A stylesheet"
|
63
|
-
provider.
|
63
|
+
expect(provider).to receive(:find_stylesheet!).with("/some/url.css").and_return stylesheet
|
64
64
|
|
65
65
|
dom = dom_fragment %(<link rel="stylesheet" href="/some/url.css">)
|
66
66
|
scanner = AssetScanner.new dom, provider
|
67
67
|
|
68
|
-
scanner.find_css.
|
68
|
+
expect(scanner.find_css).to eq([stylesheet])
|
69
69
|
end
|
70
70
|
|
71
71
|
it "ignores referenced print stylesheets" do
|
72
72
|
dom = dom_fragment %(<link rel="stylesheet" href="/error.css" media="print">)
|
73
|
-
provider.
|
73
|
+
expect(provider).not_to receive(:find_stylesheet!)
|
74
74
|
|
75
75
|
scanner = AssetScanner.new dom, provider
|
76
76
|
|
77
|
-
scanner.find_css.
|
77
|
+
expect(scanner.find_css).to eq([])
|
78
78
|
end
|
79
79
|
|
80
80
|
it "does not look for ignored referenced stylesheets" do
|
81
81
|
dom = dom_fragment %(<link rel="stylesheet" href="/error.css" data-roadie-ignore>)
|
82
|
-
provider.
|
82
|
+
expect(provider).not_to receive(:find_stylesheet!)
|
83
83
|
|
84
84
|
scanner = AssetScanner.new dom, provider
|
85
85
|
|
86
|
-
scanner.find_css.
|
86
|
+
expect(scanner.find_css).to eq([])
|
87
87
|
end
|
88
88
|
|
89
89
|
it 'ignores HTML comments and CDATA sections' do
|
@@ -97,9 +97,9 @@ module Roadie
|
|
97
97
|
scanner = AssetScanner.new dom, provider
|
98
98
|
stylesheet = scanner.find_css.first
|
99
99
|
|
100
|
-
stylesheet.to_s.
|
101
|
-
stylesheet.to_s.
|
102
|
-
stylesheet.to_s.
|
100
|
+
expect(stylesheet.to_s).to include("green")
|
101
|
+
expect(stylesheet.to_s).not_to include("!--")
|
102
|
+
expect(stylesheet.to_s).not_to include("CDATA")
|
103
103
|
end
|
104
104
|
|
105
105
|
it "does not pick up scripts generating styles" do
|
@@ -111,7 +111,7 @@ module Roadie
|
|
111
111
|
HTML
|
112
112
|
|
113
113
|
scanner = AssetScanner.new dom, provider
|
114
|
-
scanner.find_css.
|
114
|
+
expect(scanner.find_css).to eq([])
|
115
115
|
end
|
116
116
|
end
|
117
117
|
|
@@ -136,17 +136,17 @@ module Roadie
|
|
136
136
|
|
137
137
|
stylesheets = scanner.extract_css
|
138
138
|
|
139
|
-
stylesheets.
|
140
|
-
stylesheets[0].to_s.
|
141
|
-
stylesheets[1].to_s.
|
139
|
+
expect(stylesheets).to have(2).stylesheets
|
140
|
+
expect(stylesheets[0].to_s).to include("span")
|
141
|
+
expect(stylesheets[1].to_s).to include("body")
|
142
142
|
|
143
|
-
dom.
|
144
|
-
dom.
|
145
|
-
dom.
|
146
|
-
dom.
|
143
|
+
expect(dom).to have_selector("html > head > title")
|
144
|
+
expect(dom).to have_selector("html > body > style[data-roadie-ignore]")
|
145
|
+
expect(dom).to have_selector("link[data-roadie-ignore]")
|
146
|
+
expect(dom).to have_selector("link[media=print]")
|
147
147
|
|
148
|
-
dom.
|
149
|
-
dom.
|
148
|
+
expect(dom).not_to have_selector("html > head > style")
|
149
|
+
expect(dom).not_to have_selector("html > head > link[href='/some/url.css']")
|
150
150
|
end
|
151
151
|
end
|
152
152
|
end
|
@@ -4,13 +4,14 @@ module Roadie
|
|
4
4
|
describe CssNotFound do
|
5
5
|
it "is initialized with a name" do
|
6
6
|
error = CssNotFound.new('style.css')
|
7
|
-
error.css_name.
|
8
|
-
error.message.
|
7
|
+
expect(error.css_name).to eq('style.css')
|
8
|
+
expect(error.message).to eq('Could not find stylesheet "style.css"')
|
9
9
|
end
|
10
10
|
|
11
11
|
it "can be initialized with an extra message" do
|
12
|
-
CssNotFound.new('file.css', "directory is missing").message.
|
12
|
+
expect(CssNotFound.new('file.css', "directory is missing").message).to eq(
|
13
13
|
'Could not find stylesheet "file.css": directory is missing'
|
14
|
+
)
|
14
15
|
end
|
15
16
|
end
|
16
17
|
end
|
@@ -8,22 +8,22 @@ module Roadie
|
|
8
8
|
|
9
9
|
it "is initialized with HTML" do
|
10
10
|
doc = Document.new "<html></html>"
|
11
|
-
doc.html.
|
11
|
+
expect(doc.html).to eq("<html></html>")
|
12
12
|
end
|
13
13
|
|
14
14
|
it "has an accessor for URL options" do
|
15
15
|
document.url_options = {host: "foo.bar"}
|
16
|
-
document.url_options.
|
16
|
+
expect(document.url_options).to eq({host: "foo.bar"})
|
17
17
|
end
|
18
18
|
|
19
19
|
it "has a ProviderList" do
|
20
|
-
document.asset_providers.
|
20
|
+
expect(document.asset_providers).to be_instance_of(ProviderList)
|
21
21
|
end
|
22
22
|
|
23
23
|
it "defaults to having just a FilesystemProvider in the provider list" do
|
24
|
-
document.
|
24
|
+
expect(document).to have(1).asset_providers
|
25
25
|
provider = document.asset_providers.first
|
26
|
-
provider.
|
26
|
+
expect(provider).to be_instance_of(FilesystemProvider)
|
27
27
|
end
|
28
28
|
|
29
29
|
it "allows changes to the asset providers" do
|
@@ -31,11 +31,11 @@ module Roadie
|
|
31
31
|
old_list = document.asset_providers
|
32
32
|
|
33
33
|
document.asset_providers = [other_provider]
|
34
|
-
document.asset_providers.
|
35
|
-
document.asset_providers.each.to_a.
|
34
|
+
expect(document.asset_providers).to be_instance_of(ProviderList)
|
35
|
+
expect(document.asset_providers.each.to_a).to eq([other_provider])
|
36
36
|
|
37
37
|
document.asset_providers = old_list
|
38
|
-
document.asset_providers.
|
38
|
+
expect(document.asset_providers).to eq(old_list)
|
39
39
|
end
|
40
40
|
|
41
41
|
it "can store callbacks for inlining" do
|
@@ -44,8 +44,8 @@ module Roadie
|
|
44
44
|
document.before_transformation = callable
|
45
45
|
document.after_transformation = callable
|
46
46
|
|
47
|
-
document.before_transformation.
|
48
|
-
document.after_transformation.
|
47
|
+
expect(document.before_transformation).to eq(callable)
|
48
|
+
expect(document.after_transformation).to eq(callable)
|
49
49
|
end
|
50
50
|
|
51
51
|
describe "transforming" do
|
@@ -56,9 +56,9 @@ module Roadie
|
|
56
56
|
document.before_transformation = before
|
57
57
|
document.after_transformation = after
|
58
58
|
|
59
|
-
before.
|
60
|
-
Inliner.
|
61
|
-
after.
|
59
|
+
expect(before).to receive(:call).with(instance_of(Nokogiri::HTML::Document)).ordered
|
60
|
+
expect(Inliner).to receive(:new).ordered.and_return double.as_null_object
|
61
|
+
expect(after).to receive(:call).with(instance_of(Nokogiri::HTML::Document)).ordered
|
62
62
|
|
63
63
|
document.transform
|
64
64
|
end
|
@@ -82,13 +82,13 @@ module Roadie
|
|
82
82
|
|
83
83
|
result = Nokogiri::HTML.parse document.transform
|
84
84
|
|
85
|
-
result.
|
86
|
-
result.at_css('title').text.
|
85
|
+
expect(result).to have_selector('html > head > title')
|
86
|
+
expect(result.at_css('title').text).to eq("Greetings")
|
87
87
|
|
88
|
-
result.
|
88
|
+
expect(result).to have_selector('html > body > p')
|
89
89
|
paragraph = result.at_css('p')
|
90
|
-
paragraph.text.
|
91
|
-
paragraph.to_xml.
|
90
|
+
expect(paragraph.text).to eq("Hello, world!")
|
91
|
+
expect(paragraph.to_xml).to eq('<p style="color:green">Hello, world!</p>')
|
92
92
|
end
|
93
93
|
|
94
94
|
it "extracts styles from the HTML" do
|
@@ -112,7 +112,7 @@ module Roadie
|
|
112
112
|
|
113
113
|
result = Nokogiri::HTML.parse document.transform
|
114
114
|
|
115
|
-
result.
|
115
|
+
expect(result).to have_styling([
|
116
116
|
%w[color red],
|
117
117
|
%w[text-align right],
|
118
118
|
%w[color green],
|
@@ -11,11 +11,11 @@ module Roadie
|
|
11
11
|
it_behaves_like "roadie asset provider", valid_name: "stylesheets/green.css", invalid_name: "foo"
|
12
12
|
|
13
13
|
it "takes a path" do
|
14
|
-
FilesystemProvider.new("/tmp").path.
|
14
|
+
expect(FilesystemProvider.new("/tmp").path).to eq("/tmp")
|
15
15
|
end
|
16
16
|
|
17
17
|
it "defaults to the current working directory" do
|
18
|
-
FilesystemProvider.new.path.
|
18
|
+
expect(FilesystemProvider.new.path).to eq(Dir.pwd)
|
19
19
|
end
|
20
20
|
|
21
21
|
describe "finding stylesheets" do
|
@@ -24,17 +24,18 @@ module Roadie
|
|
24
24
|
file_contents = File.read full_path
|
25
25
|
|
26
26
|
stylesheet = provider.find_stylesheet("stylesheets/green.css")
|
27
|
-
stylesheet.
|
28
|
-
stylesheet.
|
27
|
+
expect(stylesheet).not_to be_nil
|
28
|
+
expect(stylesheet.name).to eq(full_path)
|
29
|
+
expect(stylesheet.to_s).to eq(Stylesheet.new("", file_contents).to_s)
|
29
30
|
end
|
30
31
|
|
31
32
|
it "returns nil on non-existant files" do
|
32
|
-
provider.find_stylesheet("non/existant.css").
|
33
|
+
expect(provider.find_stylesheet("non/existant.css")).to be_nil
|
33
34
|
end
|
34
35
|
|
35
36
|
it "finds files inside the base path when using absolute paths" do
|
36
37
|
full_path = File.join(fixtures_path, "stylesheets", "green.css")
|
37
|
-
provider.find_stylesheet("/stylesheets/green.css").name.
|
38
|
+
expect(provider.find_stylesheet("/stylesheets/green.css").name).to eq(full_path)
|
38
39
|
end
|
39
40
|
|
40
41
|
it "does not read files above the base directory" do
|
@@ -43,5 +44,27 @@ module Roadie
|
|
43
44
|
}.to raise_error FilesystemProvider::InsecurePathError
|
44
45
|
end
|
45
46
|
end
|
47
|
+
|
48
|
+
describe "finding stylesheets with query strings" do
|
49
|
+
it "ignores the query string" do
|
50
|
+
full_path = File.join(fixtures_path, "stylesheets", "green.css")
|
51
|
+
file_contents = File.read full_path
|
52
|
+
|
53
|
+
stylesheet = provider.find_stylesheet("/stylesheets/green.css?time=111")
|
54
|
+
expect(stylesheet).not_to be_nil
|
55
|
+
expect(stylesheet.name).to eq(full_path)
|
56
|
+
expect(stylesheet.to_s).to eq(Stylesheet.new("", file_contents).to_s)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "shows that the query string is ignored inside raised errors" do
|
60
|
+
begin
|
61
|
+
provider.find_stylesheet!("/foo.css?query-string")
|
62
|
+
fail "No error was raised"
|
63
|
+
rescue CssNotFound => error
|
64
|
+
expect(error.css_name).to eq("foo.css")
|
65
|
+
expect(error.to_s).to include("/foo.css?query-string")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
46
69
|
end
|
47
70
|
end
|
@@ -15,34 +15,34 @@ module Roadie
|
|
15
15
|
describe "inlining styles" do
|
16
16
|
it "inlines simple attributes" do
|
17
17
|
use_css 'p { color: green }'
|
18
|
-
rendering('<p></p>').
|
18
|
+
expect(rendering('<p></p>')).to have_styling('color' => 'green')
|
19
19
|
end
|
20
20
|
|
21
21
|
it "inlines browser-prefixed attributes" do
|
22
22
|
use_css 'p { -vendor-color: green }'
|
23
|
-
rendering('<p></p>').
|
23
|
+
expect(rendering('<p></p>')).to have_styling('-vendor-color' => 'green')
|
24
24
|
end
|
25
25
|
|
26
26
|
it "inlines CSS3 attributes" do
|
27
27
|
use_css 'p { border-radius: 2px; }'
|
28
|
-
rendering('<p></p>').
|
28
|
+
expect(rendering('<p></p>')).to have_styling('border-radius' => '2px')
|
29
29
|
end
|
30
30
|
|
31
31
|
it "keeps the order of the styles that are inlined" do
|
32
32
|
use_css 'h1 { padding: 2px; margin: 5px; }'
|
33
|
-
rendering('<h1></h1>').
|
33
|
+
expect(rendering('<h1></h1>')).to have_styling([['padding', '2px'], ['margin', '5px']])
|
34
34
|
end
|
35
35
|
|
36
36
|
it "combines multiple selectors into one" do
|
37
37
|
use_css 'p { color: green; }
|
38
38
|
.tip { float: right; }'
|
39
|
-
rendering('<p class="tip"></p>').
|
39
|
+
expect(rendering('<p class="tip"></p>')).to have_styling([['color', 'green'], ['float', 'right']])
|
40
40
|
end
|
41
41
|
|
42
42
|
it "uses the attributes with the highest specificity when conflicts arises" do
|
43
43
|
use_css ".safe { color: green; }
|
44
44
|
p { color: red; }"
|
45
|
-
rendering('<p class="safe"></p>').
|
45
|
+
expect(rendering('<p class="safe"></p>')).to have_styling([['color', 'red'], ['color', 'green']])
|
46
46
|
end
|
47
47
|
|
48
48
|
it "sorts styles by specificity order" do
|
@@ -50,11 +50,11 @@ module Roadie
|
|
50
50
|
#important { important: very; }
|
51
51
|
.important { important: yes; }'
|
52
52
|
|
53
|
-
rendering('<p class="important"></p>').
|
53
|
+
expect(rendering('<p class="important"></p>')).to have_styling([
|
54
54
|
%w[important no], %w[important yes]
|
55
55
|
])
|
56
56
|
|
57
|
-
rendering('<p class="important" id="important"></p>').
|
57
|
+
expect(rendering('<p class="important" id="important"></p>')).to have_styling([
|
58
58
|
%w[important no], %w[important yes], %w[important very]
|
59
59
|
])
|
60
60
|
end
|
@@ -62,28 +62,28 @@ module Roadie
|
|
62
62
|
it "supports multiple selectors for the same rules" do
|
63
63
|
use_css 'p, a { color: green; }'
|
64
64
|
rendering('<p></p><a></a>').tap do |document|
|
65
|
-
document.
|
66
|
-
document.
|
65
|
+
expect(document).to have_styling('color' => 'green').at_selector('p')
|
66
|
+
expect(document).to have_styling('color' => 'green').at_selector('a')
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
70
|
it "keeps !important properties" do
|
71
71
|
use_css "a { text-decoration: underline !important; }
|
72
72
|
a.hard-to-spot { text-decoration: none; }"
|
73
|
-
rendering('<a class="hard-to-spot"></a>').
|
73
|
+
expect(rendering('<a class="hard-to-spot"></a>')).to have_styling([
|
74
74
|
['text-decoration', 'none'], ['text-decoration', 'underline !important']
|
75
75
|
])
|
76
76
|
end
|
77
77
|
|
78
78
|
it "combines with already present inline styles" do
|
79
79
|
use_css "p { color: green }"
|
80
|
-
rendering('<p style="font-size: 1.1em"></p>').
|
80
|
+
expect(rendering('<p style="font-size: 1.1em"></p>')).to have_styling([['color', 'green'], ['font-size', '1.1em']])
|
81
81
|
end
|
82
82
|
|
83
83
|
it "does not override inline styles" do
|
84
84
|
use_css "p { text-transform: uppercase; color: red }"
|
85
85
|
# The two color properties are kept to make css fallbacks work correctly
|
86
|
-
rendering('<p style="color: green"></p>').
|
86
|
+
expect(rendering('<p style="color: green"></p>')).to have_styling([
|
87
87
|
['text-transform', 'uppercase'],
|
88
88
|
['color', 'red'],
|
89
89
|
['color', 'green'],
|
@@ -101,7 +101,7 @@ module Roadie
|
|
101
101
|
|
102
102
|
p.active { width: 100%; }
|
103
103
|
"
|
104
|
-
rendering('<p class="active"></p>').
|
104
|
+
expect(rendering('<p class="active"></p>')).to have_styling('width' => '100%')
|
105
105
|
end
|
106
106
|
|
107
107
|
it "does not crash on any pseudo element selectors" do
|
@@ -109,7 +109,7 @@ module Roadie
|
|
109
109
|
p.some-element { width: 100%; }
|
110
110
|
p::some-element { color: red; }
|
111
111
|
"
|
112
|
-
rendering('<p class="some-element"></p>').
|
112
|
+
expect(rendering('<p class="some-element"></p>')).to have_styling('width' => '100%')
|
113
113
|
end
|
114
114
|
|
115
115
|
it "warns on selectors that crash Nokogiri" do
|
@@ -117,7 +117,7 @@ module Roadie
|
|
117
117
|
|
118
118
|
stylesheet = Stylesheet.new "foo.css", "p[%^=foo] { color: red; }"
|
119
119
|
inliner = Inliner.new([stylesheet])
|
120
|
-
inliner.
|
120
|
+
expect(inliner).to receive(:warn).with(
|
121
121
|
%{Roadie cannot use "p[%^=foo]" (from "foo.css" stylesheet) when inlining stylesheets}
|
122
122
|
)
|
123
123
|
inliner.inline(dom)
|
@@ -130,8 +130,8 @@ module Roadie
|
|
130
130
|
"
|
131
131
|
result = rendering("<p></p> <p></p>")
|
132
132
|
|
133
|
-
result.
|
134
|
-
result.
|
133
|
+
expect(result).to have_styling([['color', 'red']]).at_selector('p:first')
|
134
|
+
expect(result).to have_styling([['color', 'red'], ['color', 'green']]).at_selector('p:last')
|
135
135
|
end
|
136
136
|
|
137
137
|
it "ignores selectors with @" do
|
@@ -13,44 +13,44 @@ module Roadie
|
|
13
13
|
# See https://github.com/sparklemotion/nokogiri/issues/984
|
14
14
|
def pending_for_buggy_jruby
|
15
15
|
# No reason to check for version yet since no existing version has a fix.
|
16
|
-
|
16
|
+
skip "Pending until Nokogiri issue #984 is fixed and released" if defined?(JRuby)
|
17
17
|
end
|
18
18
|
|
19
19
|
describe "automatic doctype" do
|
20
20
|
it "inserts a HTML5 doctype if no doctype is present" do
|
21
21
|
pending_for_buggy_jruby
|
22
|
-
improve("<html></html>").internal_subset.to_xml.
|
22
|
+
expect(improve("<html></html>").internal_subset.to_xml).to eq("<!DOCTYPE html>")
|
23
23
|
end
|
24
24
|
|
25
25
|
it "does not insert duplicate doctypes" do
|
26
26
|
html = improve('<!DOCTYPE html><html><body></body></html>').to_html
|
27
|
-
html.scan('DOCTYPE').size.
|
27
|
+
expect(html.scan('DOCTYPE').size).to eq(1)
|
28
28
|
end
|
29
29
|
|
30
30
|
it "leaves other doctypes alone" do
|
31
31
|
dtd = "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">"
|
32
32
|
html = "#{dtd}<html></html>"
|
33
|
-
improve(html).internal_subset.to_xml.strip.
|
33
|
+
expect(improve(html).internal_subset.to_xml.strip).to eq(dtd)
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
37
|
describe "basic HTML structure" do
|
38
38
|
it "inserts a <html> element as the root" do
|
39
|
-
improve("<h1>Hey!</h1>").
|
40
|
-
improve("<html></html>").css('html').size.
|
39
|
+
expect(improve("<h1>Hey!</h1>")).to have_selector("html h1")
|
40
|
+
expect(improve("<html></html>").css('html').size).to eq(1)
|
41
41
|
end
|
42
42
|
|
43
43
|
it "inserts <head> if not present" do
|
44
|
-
improve('<html><body></body></html>').
|
45
|
-
improve('<html></html>').
|
46
|
-
improve('Foo').
|
47
|
-
improve('<html><head></head></html>').css('head').size.
|
44
|
+
expect(improve('<html><body></body></html>')).to have_selector('html > head + body')
|
45
|
+
expect(improve('<html></html>')).to have_selector('html > head')
|
46
|
+
expect(improve('Foo')).to have_selector('html > head')
|
47
|
+
expect(improve('<html><head></head></html>').css('head').size).to eq(1)
|
48
48
|
end
|
49
49
|
|
50
50
|
it "inserts <body> if not present" do
|
51
|
-
improve('<h1>Hey!</h1>').
|
52
|
-
improve('<html><h1>Hey!</h1></html>').
|
53
|
-
improve('<html><body><h1>Hey!</h1></body></html>').css('body').size.
|
51
|
+
expect(improve('<h1>Hey!</h1>')).to have_selector('html > body > h1')
|
52
|
+
expect(improve('<html><h1>Hey!</h1></html>')).to have_selector('html > body > h1')
|
53
|
+
expect(improve('<html><body><h1>Hey!</h1></body></html>').css('body').size).to eq(1)
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
@@ -58,14 +58,14 @@ module Roadie
|
|
58
58
|
it "is inserted if missing" do
|
59
59
|
dom = improve('<html><head></head><body></body></html>')
|
60
60
|
|
61
|
-
dom.
|
61
|
+
expect(dom).to have_selector('head meta')
|
62
62
|
meta = dom.at_css('head meta')
|
63
|
-
meta['http-equiv'].
|
64
|
-
meta['content'].
|
63
|
+
expect(meta['http-equiv']).to eq('Content-Type')
|
64
|
+
expect(meta['content']).to eq('text/html; charset=UTF-8')
|
65
65
|
end
|
66
66
|
|
67
67
|
it "is left alone when predefined" do
|
68
|
-
improve(<<-HTML).xpath('//meta').
|
68
|
+
expect(improve(<<-HTML).xpath('//meta')).to have(1).item
|
69
69
|
<html>
|
70
70
|
<head>
|
71
71
|
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
|