arbre2 2.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.
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