roadie 3.0.0.pre1 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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" />
|