arbre2 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +30 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +6 -0
  6. data/CHANGELOG.md +75 -0
  7. data/Gemfile +2 -0
  8. data/Gemfile.lock +93 -0
  9. data/LICENSE +20 -0
  10. data/README.md +92 -0
  11. data/Rakefile +7 -0
  12. data/arbre.gemspec +28 -0
  13. data/lib/arbre/child_element_collection.rb +86 -0
  14. data/lib/arbre/container.rb +20 -0
  15. data/lib/arbre/context.rb +83 -0
  16. data/lib/arbre/element/building.rb +151 -0
  17. data/lib/arbre/element.rb +194 -0
  18. data/lib/arbre/element_collection.rb +93 -0
  19. data/lib/arbre/html/attributes.rb +91 -0
  20. data/lib/arbre/html/class_list.rb +53 -0
  21. data/lib/arbre/html/comment.rb +47 -0
  22. data/lib/arbre/html/document.rb +93 -0
  23. data/lib/arbre/html/html_tags.rb +67 -0
  24. data/lib/arbre/html/querying.rb +256 -0
  25. data/lib/arbre/html/tag.rb +317 -0
  26. data/lib/arbre/rails/layouts.rb +126 -0
  27. data/lib/arbre/rails/legacy_document.rb +29 -0
  28. data/lib/arbre/rails/rendering.rb +76 -0
  29. data/lib/arbre/rails/rspec/arbre_support.rb +61 -0
  30. data/lib/arbre/rails/rspec.rb +2 -0
  31. data/lib/arbre/rails/template_handler.rb +32 -0
  32. data/lib/arbre/rails.rb +35 -0
  33. data/lib/arbre/rspec/be_rendered_as_matcher.rb +103 -0
  34. data/lib/arbre/rspec/be_scripted_as_matcher.rb +68 -0
  35. data/lib/arbre/rspec/contain_script_matcher.rb +64 -0
  36. data/lib/arbre/rspec.rb +3 -0
  37. data/lib/arbre/text_node.rb +35 -0
  38. data/lib/arbre/version.rb +3 -0
  39. data/lib/arbre.rb +27 -0
  40. data/spec/arbre/integration/html_document_spec.rb +90 -0
  41. data/spec/arbre/integration/html_spec.rb +283 -0
  42. data/spec/arbre/integration/querying_spec.rb +187 -0
  43. data/spec/arbre/integration/rails_spec.rb +183 -0
  44. data/spec/arbre/rails/rspec/arbre_support_spec.rb +75 -0
  45. data/spec/arbre/rspec/be_rendered_as_matcher_spec.rb +80 -0
  46. data/spec/arbre/rspec/be_scripted_as_matcher_spec.rb +61 -0
  47. data/spec/arbre/rspec/contain_script_matcher_spec.rb +40 -0
  48. data/spec/arbre/support/arbre_example_group.rb +0 -0
  49. data/spec/arbre/unit/child_element_collection_spec.rb +146 -0
  50. data/spec/arbre/unit/container_spec.rb +23 -0
  51. data/spec/arbre/unit/context_spec.rb +95 -0
  52. data/spec/arbre/unit/element/building_spec.rb +300 -0
  53. data/spec/arbre/unit/element_collection_spec.rb +169 -0
  54. data/spec/arbre/unit/element_spec.rb +297 -0
  55. data/spec/arbre/unit/html/attributes_spec.rb +219 -0
  56. data/spec/arbre/unit/html/class_list_spec.rb +109 -0
  57. data/spec/arbre/unit/html/comment_spec.rb +42 -0
  58. data/spec/arbre/unit/html/querying_spec.rb +32 -0
  59. data/spec/arbre/unit/html/tag_spec.rb +300 -0
  60. data/spec/arbre/unit/rails/layouts_spec.rb +127 -0
  61. data/spec/arbre/unit/text_node_spec.rb +40 -0
  62. data/spec/rails/app/controllers/example_controller.rb +18 -0
  63. data/spec/rails/app/views/example/_arbre_partial.html.arb +7 -0
  64. data/spec/rails/app/views/example/_erb_partial.html.erb +1 -0
  65. data/spec/rails/app/views/example/arbre.html.arb +1 -0
  66. data/spec/rails/app/views/example/arbre_partial_result.html.arb +3 -0
  67. data/spec/rails/app/views/example/erb.html.erb +5 -0
  68. data/spec/rails/app/views/example/erb_partial_result.html.arb +3 -0
  69. data/spec/rails/app/views/example/partials.html.arb +11 -0
  70. data/spec/rails/app/views/layouts/empty.html.arb +1 -0
  71. data/spec/rails/app/views/layouts/with_title.html.arb +5 -0
  72. data/spec/rails/config/routes.rb +4 -0
  73. data/spec/rails_spec_helper.rb +13 -0
  74. data/spec/spec_helper.rb +20 -0
  75. data/spec/support/arbre_example_group.rb +19 -0
  76. metadata +254 -0
@@ -0,0 +1,183 @@
1
+ require 'rails_spec_helper'
2
+
3
+ describe Arbre::Rails, :type => :request do
4
+
5
+ # Describes Rails integration. Refer to spec/rails/example_app for an example application.
6
+ # The application offers one controller action mapped to the root path, which can take
7
+ # the name of a template and/or a layout to render.
8
+
9
+ let(:body) { response.body }
10
+
11
+ ######
12
+ # Content / layout
13
+
14
+ it "should render an ERB template without a layout" do
15
+ get '/', :template => 'erb', :layout => false
16
+ expect(body).to be_rendered_as('<h1>This is an ERB template</h1>', escape: false)
17
+ end
18
+
19
+ it "should render an Arbre template without a layout" do
20
+ get '/', :template => 'arbre', :layout => false
21
+ expect(body).to be_rendered_as('<h1>This is an Arbre template</h1>', escape: false)
22
+ end
23
+
24
+ it "should render an ERB template with an empty Arbre layout" do
25
+ get '/', :template => 'erb', :layout => 'empty'
26
+ expect(body).to be_rendered_as(<<-HTML, escape: false)
27
+ <!DOCTYPE html>
28
+
29
+ <html>
30
+ <head>
31
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
32
+ <meta http-equiv="Author" content="Me" />
33
+ </head>
34
+ <body>
35
+ <h1>This is an ERB template</h1>
36
+ </body>
37
+ </html>
38
+ HTML
39
+ end
40
+
41
+ it "should render an ERB template with an Arbre layout that sets a title" do
42
+ get '/', :template => 'erb', :layout => 'with_title'
43
+ expect(body).to be_rendered_as(<<-HTML, escape: false)
44
+ <!DOCTYPE html>
45
+
46
+ <html>
47
+ <head>
48
+ <title>Application Title</title>
49
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
50
+ <meta http-equiv="Author" content="Me" />
51
+ </head>
52
+ <body>
53
+ <h1>This is an ERB template</h1>
54
+ </body>
55
+ </html>
56
+ HTML
57
+ end
58
+
59
+ it "should allow the legacy document class to be overridden" do
60
+ Arbre::Rails.legacy_document = Class.new(Arbre::Html::Document) do
61
+ def build!
62
+ super
63
+
64
+ head do
65
+ text_node helpers.content_for(:head)
66
+ text_node helpers.content_for(:styles)
67
+ end
68
+ body do
69
+ div id: 'content-container' do
70
+ text_node helpers.content_for(:layout)
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ get '/', :template => 'erb', :layout => 'empty'
77
+ expect(body).to be_rendered_as(<<-HTML, escape: false)
78
+ <!DOCTYPE html>
79
+
80
+ <html>
81
+ <head>
82
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
83
+ <meta http-equiv="Author" content="Me" />
84
+ </head>
85
+ <body>
86
+ <div id="content-container">
87
+ <h1>This is an ERB template</h1>
88
+ </div>
89
+ </body>
90
+ </html>
91
+ HTML
92
+
93
+ Arbre::Rails.legacy_document = nil
94
+ end
95
+
96
+ it "should render an Arbre template with an empty Arbre layout" do
97
+ get '/', :template => 'arbre', :layout => 'empty'
98
+ expect(body).to be_rendered_as(<<-HTML, escape: false)
99
+ <!DOCTYPE html>
100
+
101
+ <html>
102
+ <head>
103
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
104
+ </head>
105
+ <body>
106
+ <h1>This is an Arbre template</h1>
107
+ </body>
108
+ </html>
109
+ HTML
110
+ end
111
+
112
+ it "should render an Arbre template with an Arbre layout that sets a title" do
113
+ get '/', :template => 'arbre', :layout => 'with_title'
114
+ expect(body).to be_rendered_as(<<-HTML, escape: false)
115
+ <!DOCTYPE html>
116
+
117
+ <html>
118
+ <head>
119
+ <title>Application Title</title>
120
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
121
+ </head>
122
+ <body>
123
+ <h1>This is an Arbre template</h1>
124
+ </body>
125
+ </html>
126
+ HTML
127
+ end
128
+
129
+ ######
130
+ # Partial / sub-template rendering
131
+
132
+ it "should re-use a context when using method `partial' and the partial is also Arbre" do
133
+ get '/', :template => 'partials', :layout => false
134
+
135
+ expect(body).to be_rendered_as(%r[
136
+ <p>Main template: Context Object ID=(\d+)</p>
137
+ <div id="arbre">
138
+ <p>Partial: Local1=local1, Context Object ID=(\d+)</p>
139
+ <p>Paragraph 2</p>
140
+ </div>
141
+ <div id="arbre-using-render">
142
+ <p>Partial: Context Object ID=(\d+)</p>
143
+ <p>Paragraph 2</p>
144
+ </div>
145
+ <div id="erb">
146
+ <p>ERB template.</p>
147
+ </div>
148
+ ]x, escape: false)
149
+
150
+ # Make sure that the context is re-used between the first two, but not in the case of 'render'.
151
+ (ctx1_id,_), (ctx2_id,_), (ctx3_id,_) = body.scan(/Context Object ID=(\d+)/)
152
+ expect(ctx1_id).to eql(ctx2_id)
153
+ expect(ctx1_id).not_to eql(ctx3_id)
154
+ end
155
+
156
+ it "should return an empty string if an Arbre context is re-used" do
157
+ get '/partial', :context => true
158
+ expect(body).to be_rendered_as('', escape: false)
159
+ end
160
+
161
+ it "should not return an empty string if an Arbre context is not re-used" do
162
+ get '/partial', :context => false
163
+ expect(body).to be_rendered_as(%r[^<p>Partial: Context Object ID=(\d+)</p>], escape: false)
164
+ end
165
+
166
+ it "should handle an Arbre template without converting the template to a string" do
167
+ get '/', :template => 'arbre_partial_result', :layout => false
168
+ expect(body).to be_rendered_as(%r[
169
+ <p>Partial: Context Object ID=(\d+)</p>
170
+ <p>Paragraph 2</p>
171
+ <p>The previous element is a Arbre::Html::P</p>
172
+ ]x, escape: false)
173
+ end
174
+
175
+ it "should wrap any other partial in a TextNode" do
176
+ get '/', :template => 'erb_partial_result', :layout => false
177
+ expect(body).to be_rendered_as(%r[
178
+ <p>ERB template.</p>
179
+ <p>The previous element is a Arbre::TextNode</p>
180
+ ]x, escape: false)
181
+ end
182
+
183
+ end
@@ -0,0 +1,75 @@
1
+ require 'rails_spec_helper'
2
+
3
+ describe Arbre::Rails::RSpec::ArbreSupport, arbre: true do
4
+
5
+ let(:example) { self }
6
+ subject { example }
7
+
8
+ describe '#arbre_context' do
9
+ let(:assigns) { double(:assigns) }
10
+ let(:helpers) { double(:helpers) }
11
+
12
+ it "should build and memoize an Arbre context" do
13
+ context = double(:context)
14
+ expect(Arbre::Context).to receive(:new).once.with(assigns, helpers).and_return(context)
15
+ expect(example.arbre_context).to be(context)
16
+ end
17
+
18
+ it "should be aliased as #arbre" do
19
+ context = double(:context)
20
+ expect(Arbre::Context).to receive(:new).once.with(assigns, helpers).and_return(context)
21
+ expect(example.arbre_context).to be(context)
22
+ expect(example.arbre).to be(context)
23
+ end
24
+ end
25
+
26
+ its(:assigns) { should eql({}) }
27
+
28
+ describe '#helpers' do
29
+ it "should build and memoize helpers" do
30
+ helpers = double(:helpers)
31
+ expect(example).to receive(:build_helpers).once.and_return(helpers)
32
+ expect(example.helpers).to be(helpers)
33
+ expect(example.helpers).to be(helpers)
34
+ end
35
+ end
36
+
37
+ describe '#build_helpers' do
38
+ let(:helpers) { example.build_helpers }
39
+
40
+ specify { expect(helpers).to be_a(ActionView::Base) }
41
+ specify { expect(helpers.controller).to be(controller) }
42
+ specify { expect(helpers.request).to be(request) }
43
+
44
+ it "should mock an asset_path helper" do
45
+ expect(helpers.asset_path('test')).to eql('/assets/test')
46
+ end
47
+
48
+ it "should include any ApplicationController helpers if an ApplicationController exists" do
49
+ if defined?(::ApplicationController)
50
+ prev_app_controller = ::ApplicationController
51
+ Object.send :remove_const, :ApplicationController
52
+ end
53
+ ::ApplicationController = Class.new(ActionController::Base)
54
+ app_helpers = Module.new do
55
+ def my_method; 'result' end
56
+ end
57
+ expect(::ApplicationController).to receive(:_helpers).and_return(app_helpers)
58
+
59
+ expect(helpers.my_method).to eql('result')
60
+ Object.send :remove_const, :ApplicationController
61
+ ::ApplicationController = prev_app_controller if prev_app_controller
62
+ end
63
+
64
+ end
65
+
66
+ describe '#controller' do
67
+ specify { expect(example.controller).to be_a(ActionController::Base) }
68
+ specify { expect(example.controller.request).to be(example.request) }
69
+ end
70
+
71
+ describe '#request' do
72
+ specify { expect(example.request).to be_a(ActionDispatch::Request) }
73
+ end
74
+
75
+ end
@@ -0,0 +1,80 @@
1
+ require 'spec_helper'
2
+
3
+ describe Arbre::RSpec::BeRenderedAsMatcher do
4
+
5
+ it "should fail if the actual was nil" do
6
+ expect{ expect(nil).to be_rendered_as('<html/>') }
7
+ .to raise_error(RSpec::Expectations::ExpectationNotMetError, <<-STR.gsub(/^\s{8}/, ''))
8
+ expected that element of type NilClass would be rendered differently:
9
+ expected: <html/> (String)
10
+ got: nil
11
+ STR
12
+ end
13
+
14
+ it "should fail if the actual's string version was not the same" do
15
+ expect{ expect(double(:to_s => '<html></html>'.html_safe)).to be_rendered_as('<html/>') }
16
+ .to raise_error(RSpec::Expectations::ExpectationNotMetError, <<-STR.gsub(/^\s{8}/, ''))
17
+ expected that element of type RSpec::Mocks::Mock would be rendered differently:
18
+ expected: <html/> (String)
19
+ got: <html></html>
20
+ STR
21
+ end
22
+
23
+ it "should fail if the actual's string version did not match the regular expression" do
24
+ expect{ expect(double(:to_s => '<html></html>'.html_safe)).to be_rendered_as(/regular* expression{1,2}/) }
25
+ .to raise_error(RSpec::Expectations::ExpectationNotMetError, <<-STR.gsub(/^\s{8}/, ''))
26
+ expected that element of type RSpec::Mocks::Mock would be rendered differently:
27
+ expected: /regular* expression{1,2}/ (Regexp)
28
+ got: <html></html>
29
+ STR
30
+ end
31
+
32
+ it "should fail if the actual's string was not HTML-safed" do
33
+ expect{ expect(double(:to_s => '<html></html>')).to be_rendered_as('<html></html>') }
34
+ .to raise_error(RSpec::Expectations::ExpectationNotMetError, <<-STR.gsub(/^\s{8}/, ''))
35
+ expected that element of type RSpec::Mocks::Mock would be rendered differently:
36
+ expected: <html></html> (String)
37
+ got: &lt;html&gt;&lt;/html&gt;
38
+ STR
39
+ end
40
+
41
+ it "should pass if the actual's string version did match the given string" do
42
+ expect{ expect('<html></html>'.html_safe).to be_rendered_as('<html></html>') }
43
+ .not_to raise_error
44
+ end
45
+
46
+ it "should pass if the actual's string version did match the given regular expression" do
47
+ expect{ expect('<html></html>'.html_safe).to be_rendered_as(/<html>.*?<\/html>/) }
48
+ .not_to raise_error
49
+ end
50
+
51
+ it "should pass if the actual's string version did match the given string, where whitespace is ignored" do
52
+ expect{ expect('<html> </html>'.html_safe).to be_rendered_as('<html></html>') }
53
+ .not_to raise_error
54
+ expect{ expect("<html>\n</html>\n".html_safe).to be_rendered_as('<html> </html>') }
55
+ .not_to raise_error
56
+ end
57
+
58
+ it "should pass if the actual's string version did match the given regular expression, where whitespace is ignored" do
59
+ expect{ expect('<html> </html>'.html_safe).to be_rendered_as(/<html>.*?<\/html>/) }
60
+ .not_to raise_error
61
+ expect{ expect("<html>\n</html>\n".html_safe).to be_rendered_as(/<html.*> <\/html>/) }
62
+ .not_to raise_error
63
+ end
64
+
65
+ it "should pass if the actual's string version did match the given string, where attribute order is ignored" do
66
+ expect{ expect('<html lang="en" data-something="two"></html>'.html_safe).to be_rendered_as('<html data-something="two" lang="en"></html>') }
67
+ .not_to raise_error
68
+ end
69
+
70
+ it "should pass if the actual's string version did match the given regex, where attribute order is ignored" do
71
+ expect{ expect('<html lang="en" data-something="two"></html>'.html_safe).to be_rendered_as(/<html data-something="two" lang="en">.*<\/html>/) }
72
+ .not_to raise_error
73
+ end
74
+
75
+ it "should pass if the actual's string version matched the given string, where placeholders were used" do
76
+ expect{ expect('<html><body></body></html>'.html_safe).to be_rendered_as('<html>(...)</html>') }
77
+ .not_to raise_error
78
+ end
79
+
80
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe Arbre::RSpec::BeScriptedAsMatcher do
4
+
5
+ it "should fail if the actual's content was not the same" do
6
+ expect{ expect(double(:content => 'alert("test");')).to be_scripted_as('alert("something else");') }
7
+ .to raise_error(RSpec::Expectations::ExpectationNotMetError, <<-STR.gsub(/^\s{8}/, ''))
8
+ expected that element of type RSpec::Mocks::Mock would be scripted differently:
9
+ expected: alert("something else"); (String)
10
+ got: alert("test");
11
+ STR
12
+ end
13
+
14
+ it "should fail if the actual's content did not match the regular expression" do
15
+ expect{ expect(double(:content => 'alert("test");')).to be_scripted_as(/regular* expression{1,2}/) }
16
+ .to raise_error(RSpec::Expectations::ExpectationNotMetError, <<-STR.gsub(/^\s{8}/, ''))
17
+ expected that element of type RSpec::Mocks::Mock would be scripted differently:
18
+ expected: /regular* expression{1,2}/ (Regexp)
19
+ got: alert("test");
20
+ STR
21
+ end
22
+
23
+ it "should pass if the actual's content did match the given string" do
24
+ expect{ expect(double(:content => 'alert("test");')).to be_scripted_as('alert("test");') }
25
+ .not_to raise_error
26
+ end
27
+
28
+ it "should pass if the actual's content did match the given regular expression" do
29
+ expect{ expect(double(:content => 'alert("test");')).to be_scripted_as(/alert\("\w+"\);/) }
30
+ .not_to raise_error
31
+ end
32
+
33
+ it "should pass if the actual's content did match the given string, where whitespace is ignored" do
34
+ expect{ expect(double(:content => ' alert("test"); ')).to be_scripted_as('alert("test");') }
35
+ .not_to raise_error
36
+ expect{ expect(double(:content => "alert(\"test\");\n")).to be_scripted_as(' alert("test"); ') }
37
+ .not_to raise_error
38
+ end
39
+
40
+ it "should fail if the whitespace difference was significant" do
41
+ expect{ expect(double(:content => 'alert("test " );')).to be_scripted_as('alert("test");') }
42
+ .to raise_error(RSpec::Expectations::ExpectationNotMetError, <<-STR.gsub(/^\s{8}/, ''))
43
+ expected that element of type RSpec::Mocks::Mock would be scripted differently:
44
+ expected: alert("test"); (String)
45
+ got: alert("test " );
46
+ STR
47
+ end
48
+
49
+ it "should pass if the actual's content did match the given regular expression, where whitespace is ignored" do
50
+ expect{ expect(double(:content => ' alert("test"); ')).to be_scripted_as(/alert\("\w+"\);/) }
51
+ .not_to raise_error
52
+ expect{ expect(double(:content => "alert(\"test\");\n")).to be_scripted_as(/ alert\("\w+"\); /) }
53
+ .not_to raise_error
54
+ end
55
+
56
+ it "should pass if the actual's content matched the given string, where placeholders were used" do
57
+ expect{ expect(double(:content => 'var a=1; alert("test");')).to be_scripted_as('(...)alert("test");') }
58
+ .not_to raise_error
59
+ end
60
+
61
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ describe Arbre::RSpec::ContainScriptMatcher do
4
+
5
+ it "should fail if the actual's content did not contain the given script" do
6
+ expect{ expect(double(:to_s => '<script type="javascript">alert("test");</script>')).to contain_script('alert("something else");') }
7
+ .to raise_error(RSpec::Expectations::ExpectationNotMetError, <<-STR.gsub(/^\s{8}/, ''))
8
+ expected that element of type RSpec::Mocks::Mock contained script:
9
+ expected: alert("something else"); (String)
10
+ got: <script type="javascript">alert("test");</script>
11
+ STR
12
+ end
13
+
14
+ it "should pass if the actual's content did match the given string" do
15
+ expect{ expect(double(:to_s => '<script type="javascript">alert("test");</script>')).to contain_script('alert("test");') }
16
+ .not_to raise_error
17
+ end
18
+
19
+ it "should pass if the actual's content contained given string" do
20
+ expect{ expect(double(:to_s => '<body><script type="javascript">var a = 1; alert("test");</script></body>')).to contain_script('alert("test");') }
21
+ .not_to raise_error
22
+ end
23
+
24
+ it "should pass if the actual's content did match the given string, where whitespace is ignored" do
25
+ expect{ expect(double(:to_s => '<script type="javascript"> alert("test"); </script>')).to contain_script('alert("test");') }
26
+ .not_to raise_error
27
+ expect{ expect(double(:to_s => "<script type=\"javascript\">alert(\"test\");\n</script>")).to contain_script(' alert("test"); ') }
28
+ .not_to raise_error
29
+ end
30
+
31
+ it "should fail if the whitespace difference was significant" do
32
+ expect{ expect(double(:to_s => '<script type="javascript">alert("test " );</script>')).to contain_script('alert("test");') }
33
+ .to raise_error(RSpec::Expectations::ExpectationNotMetError, <<-STR.gsub(/^\s{8}/, ''))
34
+ expected that element of type RSpec::Mocks::Mock contained script:
35
+ expected: alert("test"); (String)
36
+ got: <script type="javascript">alert("test " );</script>
37
+ STR
38
+ end
39
+
40
+ end
File without changes
@@ -0,0 +1,146 @@
1
+ require 'spec_helper'
2
+ include Arbre
3
+
4
+ describe ChildElementCollection do
5
+
6
+ specify { expect(ChildElementCollection).to be < ElementCollection }
7
+
8
+ let(:parent) { Element.new }
9
+ let(:collection) { ChildElementCollection.new(parent) }
10
+
11
+ let(:element) { Element.new }
12
+ let(:element1) { Element.new }
13
+ let(:element2) { Element.new }
14
+ let(:element3) { Element.new }
15
+
16
+ ######
17
+ # Parent
18
+
19
+ it "should store its parent" do
20
+ expect(collection.parent).to be(parent)
21
+ end
22
+
23
+ it "should only be eql? to another collection if the parent is the same" do
24
+ collection1 = ChildElementCollection.new(parent)
25
+ collection1 << element1
26
+
27
+ collection2 = ChildElementCollection.new(parent)
28
+ collection2 << element1
29
+ expect(collection1).to eql(collection2)
30
+
31
+ collection2 = ChildElementCollection.new(Element.new)
32
+ collection2 << element1
33
+ expect(collection1).not_to eql(collection2)
34
+ end
35
+
36
+ it "should set the parent to each child element that is added to the collection" do
37
+ collection << element1
38
+ expect(element1.parent).to be(parent)
39
+
40
+ collection = ChildElementCollection.new(parent)
41
+ collection.insert_at 0, element2
42
+ expect(element2.parent).to be(parent)
43
+ end
44
+
45
+ it "should remove any element that is added to the collection from its existing parent" do
46
+ expect(element1).to receive(:remove!)
47
+ expect(element2).to receive(:remove!)
48
+
49
+ collection << element1
50
+ collection.insert_at 0, element2
51
+ end
52
+
53
+ it "should unset the parent from each child element that is removed from the collection" do
54
+ collection << element
55
+ collection.remove element
56
+ expect(element.parent).to be_nil
57
+ end
58
+
59
+ it "should not add or set the parent of the same element twice" do
60
+ expect(element).to receive(:parent=).once.with(parent)
61
+ collection << element << element
62
+ expect(collection).to have(1).item
63
+
64
+ collection = ChildElementCollection.new(parent)
65
+ expect(element).to receive(:parent=).once.with(parent)
66
+ collection << element
67
+ collection.insert_at 0, element
68
+ expect(collection).to have(1).item
69
+ end
70
+
71
+ it "should not unset the parent if the given element was not part of the collection" do
72
+ element.parent = Element.new
73
+ collection.remove element
74
+ expect(element.parent).not_to be_nil
75
+ end
76
+
77
+ it "should not the parents of all elements if #clear is used" do
78
+ collection << element1 << element2
79
+
80
+ expect(element1.parent).not_to be_nil
81
+ expect(element2.parent).not_to be_nil
82
+ collection.clear
83
+ expect(element1.parent).to be_nil
84
+ expect(element2.parent).to be_nil
85
+ end
86
+
87
+ ######
88
+ # Inserting
89
+
90
+ describe '#insert_at' do
91
+ it "should insert the element at the given index" do
92
+ collection << element1 << element3
93
+ collection.insert_at 1, element2
94
+
95
+ expect(collection).to eq([element1, element2, element3])
96
+ end
97
+
98
+ it "should move, and not duplicate, an element that already existed in the collection" do
99
+ collection << element1 << element3 << element2
100
+ collection.insert_at 1, element2
101
+ expect(collection).to eq([element1, element2, element3])
102
+ end
103
+
104
+ it "should be able to move an element towards the back" do
105
+ collection << element2 << element1 << element3
106
+ collection.insert_at 2, element2
107
+ expect(collection).to eq([element1, element2, element3])
108
+ end
109
+
110
+ end
111
+
112
+ describe '#insert_after' do
113
+ it "should insert the element after the other element" do
114
+ collection << element1
115
+ collection.insert_after element1, element3
116
+ collection.insert_after element1, element2
117
+
118
+ expect(collection).to eq([element1, element2, element3])
119
+ end
120
+
121
+ it "should raise an error if the given reference element did not exist in the collection" do
122
+ collection << element1
123
+ expect(element2).to receive(:to_s).and_return('element2')
124
+ expect { collection.insert_after element2, element3 }.to \
125
+ raise_error(ArgumentError, 'existing element element2 not found')
126
+ end
127
+ end
128
+
129
+ describe '#insert_before' do
130
+ it "should insert the element after the other element" do
131
+ collection << element3
132
+ collection.insert_before element3, element1
133
+ collection.insert_before element3, element2
134
+
135
+ expect(collection).to eq([element1, element2, element3])
136
+ end
137
+
138
+ it "should raise an error if the given reference element did not exist in the collection" do
139
+ collection << element1
140
+ expect(element2).to receive(:to_s).and_return('element2')
141
+ expect { collection.insert_before element2, element3 }.to \
142
+ raise_error(ArgumentError, 'existing element element2 not found')
143
+ end
144
+ end
145
+
146
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+ include Arbre
3
+
4
+ describe Container do
5
+
6
+ it "should render its content" do
7
+ container = Container.new
8
+ expect(container).to receive(:content).and_return('(CONTENT)')
9
+ expect(container.to_s).to eql('(CONTENT)')
10
+ end
11
+
12
+ it "should have an indentation level of 0 by default" do
13
+ expect(Container.new.indent_level).to eql(0)
14
+ end
15
+
16
+ it "should have the same indentation level as its parent" do
17
+ container = Container.new
18
+ container.parent = Element.new
19
+ expect(container.parent).to receive(:indent_level).and_return(5)
20
+ expect(container.indent_level).to eql(5)
21
+ end
22
+
23
+ end