hanami 2.0.3 → 2.1.0.beta1

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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -0
  3. data/LICENSE.md +1 -1
  4. data/README.md +25 -9
  5. data/hanami.gemspec +2 -2
  6. data/lib/hanami/config/actions.rb +0 -4
  7. data/lib/hanami/config/views.rb +0 -4
  8. data/lib/hanami/config.rb +54 -0
  9. data/lib/hanami/extensions/action/slice_configured_action.rb +15 -7
  10. data/lib/hanami/extensions/action.rb +4 -4
  11. data/lib/hanami/extensions/router/errors.rb +58 -0
  12. data/lib/hanami/extensions/view/context.rb +129 -60
  13. data/lib/hanami/extensions/view/part.rb +26 -0
  14. data/lib/hanami/extensions/view/scope.rb +26 -0
  15. data/lib/hanami/extensions/view/slice_configured_context.rb +0 -2
  16. data/lib/hanami/extensions/view/slice_configured_helpers.rb +44 -0
  17. data/lib/hanami/extensions/view/slice_configured_view.rb +106 -21
  18. data/lib/hanami/extensions/view/standard_helpers.rb +14 -0
  19. data/lib/hanami/extensions.rb +10 -3
  20. data/lib/hanami/helpers/form_helper/form_builder.rb +1391 -0
  21. data/lib/hanami/helpers/form_helper/values.rb +75 -0
  22. data/lib/hanami/helpers/form_helper.rb +213 -0
  23. data/lib/hanami/middleware/public_errors_app.rb +75 -0
  24. data/lib/hanami/middleware/render_errors.rb +93 -0
  25. data/lib/hanami/slice.rb +27 -2
  26. data/lib/hanami/slice_configurable.rb +3 -2
  27. data/lib/hanami/version.rb +1 -1
  28. data/lib/hanami/web/rack_logger.rb +1 -1
  29. data/lib/hanami.rb +1 -1
  30. data/spec/integration/action/view_rendering/view_context_spec.rb +221 -0
  31. data/spec/integration/action/view_rendering_spec.rb +0 -18
  32. data/spec/integration/rack_app/middleware_spec.rb +23 -23
  33. data/spec/integration/rack_app/rack_app_spec.rb +5 -1
  34. data/spec/integration/view/config/default_context_spec.rb +149 -0
  35. data/spec/integration/view/{inflector_spec.rb → config/inflector_spec.rb} +1 -1
  36. data/spec/integration/view/config/part_class_spec.rb +147 -0
  37. data/spec/integration/view/config/part_namespace_spec.rb +103 -0
  38. data/spec/integration/view/config/paths_spec.rb +119 -0
  39. data/spec/integration/view/config/scope_class_spec.rb +147 -0
  40. data/spec/integration/view/config/scope_namespace_spec.rb +103 -0
  41. data/spec/integration/view/config/template_spec.rb +38 -0
  42. data/spec/integration/view/context/request_spec.rb +3 -7
  43. data/spec/integration/view/helpers/form_helper_spec.rb +174 -0
  44. data/spec/integration/view/helpers/part_helpers_spec.rb +124 -0
  45. data/spec/integration/view/helpers/scope_helpers_spec.rb +84 -0
  46. data/spec/integration/view/helpers/user_defined_helpers/part_helpers_spec.rb +162 -0
  47. data/spec/integration/view/helpers/user_defined_helpers/scope_helpers_spec.rb +119 -0
  48. data/spec/integration/view/slice_configuration_spec.rb +9 -9
  49. data/spec/integration/web/render_detailed_errors_spec.rb +90 -0
  50. data/spec/integration/web/render_errors_spec.rb +240 -0
  51. data/spec/spec_helper.rb +1 -1
  52. data/spec/support/matchers.rb +32 -0
  53. data/spec/unit/hanami/config/actions/default_values_spec.rb +0 -4
  54. data/spec/unit/hanami/config/render_detailed_errors_spec.rb +25 -0
  55. data/spec/unit/hanami/config/render_errors_spec.rb +25 -0
  56. data/spec/unit/hanami/config/views_spec.rb +0 -18
  57. data/spec/unit/hanami/extensions/view/context_spec.rb +59 -0
  58. data/spec/unit/hanami/helpers/form_helper_spec.rb +2826 -0
  59. data/spec/unit/hanami/router/errors/not_allowed_error_spec.rb +27 -0
  60. data/spec/unit/hanami/router/errors/not_found_error_spec.rb +22 -0
  61. data/spec/unit/hanami/slice_configurable_spec.rb +18 -0
  62. data/spec/unit/hanami/version_spec.rb +1 -1
  63. data/spec/unit/hanami/web/rack_logger_spec.rb +1 -1
  64. metadata +65 -33
  65. data/spec/integration/action/view_integration_spec.rb +0 -165
  66. data/spec/integration/view/part_namespace_spec.rb +0 -96
  67. data/spec/integration/view/path_spec.rb +0 -56
  68. data/spec/integration/view/template_spec.rb +0 -68
  69. data/spec/isolation/hanami/application/already_configured_spec.rb +0 -19
  70. data/spec/isolation/hanami/application/inherit_anonymous_class_spec.rb +0 -10
  71. data/spec/isolation/hanami/application/inherit_concrete_class_spec.rb +0 -14
  72. data/spec/isolation/hanami/application/not_configured_spec.rb +0 -9
  73. data/spec/isolation/hanami/application/routes/configured_spec.rb +0 -44
  74. data/spec/isolation/hanami/application/routes/not_configured_spec.rb +0 -16
  75. data/spec/isolation/hanami/boot/success_spec.rb +0 -50
@@ -0,0 +1,221 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe "App action / View rendering / View context", :app_integration do
4
+ subject(:context) {
5
+ # We capture the context during rendering via our view spies; see the view classes below
6
+ action.call("REQUEST_METHOD" => "GET", "QUERY_STRING" => "/mock_request")
7
+ action.view.called_with[:context]
8
+ }
9
+
10
+ before do
11
+ with_directory(make_tmp_directory) do
12
+ write "config/app.rb", <<~RUBY
13
+ module TestApp
14
+ class App < Hanami::App
15
+ end
16
+ end
17
+ RUBY
18
+
19
+ write "app/action.rb", <<~RUBY
20
+ # auto_register: false
21
+
22
+ require "hanami/view"
23
+
24
+ module TestApp
25
+ class Action < Hanami::Action
26
+ end
27
+ end
28
+ RUBY
29
+
30
+ before_prepare if respond_to?(:before_prepare)
31
+ require "hanami/prepare"
32
+ end
33
+ end
34
+
35
+ describe "app action" do
36
+ let(:action) { TestApp::App["actions.posts.show"] }
37
+
38
+ def before_prepare
39
+ write "app/actions/posts/show.rb", <<~RUBY
40
+ module TestApp
41
+ module Actions
42
+ module Posts
43
+ class Show < TestApp::Action
44
+ end
45
+ end
46
+ end
47
+ end
48
+ RUBY
49
+
50
+ # Custom view class as a spy for `#call` args
51
+ write "app/views/posts/show.rb", <<~RUBY
52
+ module TestApp
53
+ module Views
54
+ module Posts
55
+ class Show
56
+ attr_reader :called_with
57
+
58
+ def call(**args)
59
+ @called_with = args
60
+ ""
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ RUBY
67
+ end
68
+
69
+ context "no context class defined" do
70
+ it "defines and uses a context class" do
71
+ expect(context).to be_an_instance_of TestApp::Views::Context
72
+ expect(context.class).to be < Hanami::View::Context
73
+ end
74
+
75
+ it "includes the request" do
76
+ expect(context.request).to be_an_instance_of Hanami::Action::Request
77
+ expect(context.request.env["QUERY_STRING"]).to eq "/mock_request"
78
+ end
79
+ end
80
+
81
+ context "context class defined" do
82
+ def before_prepare
83
+ super()
84
+
85
+ write "app/views/context.rb", <<~RUBY
86
+ # auto_register: false
87
+
88
+ module TestApp
89
+ module Views
90
+ class Context < Hanami::View::Context
91
+ def concrete_app_context?
92
+ true
93
+ end
94
+ end
95
+ end
96
+ end
97
+ RUBY
98
+ end
99
+
100
+ it "uses the defined context class" do
101
+ expect(context).to be_an_instance_of TestApp::Views::Context
102
+ expect(context).to be_a_concrete_app_context
103
+ end
104
+ end
105
+
106
+ context "hanami-view not bundled" do
107
+ before do
108
+ allow(Hanami).to receive(:bundled?).and_call_original
109
+ expect(Hanami).to receive(:bundled?).with("hanami-view").and_return false
110
+ end
111
+
112
+ it "does not provide a context" do
113
+ expect(context).to be nil
114
+ end
115
+
116
+ context "context class defined" do
117
+ def before_prepare
118
+ super()
119
+
120
+ write "app/views/context.rb", <<~RUBY
121
+ module TestApp
122
+ module Views
123
+ class Context
124
+ def initialize(**)
125
+ end
126
+
127
+ def with(**)
128
+ self
129
+ end
130
+
131
+ def concrete_app_context?
132
+ true
133
+ end
134
+ end
135
+ end
136
+ end
137
+ RUBY
138
+ end
139
+
140
+ it "uses the defined context class" do
141
+ expect(context).to be_an_instance_of TestApp::Views::Context
142
+ expect(context).to be_a_concrete_app_context
143
+ end
144
+ end
145
+ end
146
+ end
147
+
148
+ describe "slice action" do
149
+ let(:action) { Main::Slice["actions.posts.show"] }
150
+
151
+ def before_prepare
152
+ write "slices/main/action.rb", <<~RUBY
153
+ module Main
154
+ class Action < TestApp::Action
155
+ end
156
+ end
157
+ RUBY
158
+
159
+ write "slices/main/actions/posts/show.rb", <<~RUBY
160
+ module Main
161
+ module Actions
162
+ module Posts
163
+ class Show < Main::Action
164
+ end
165
+ end
166
+ end
167
+ end
168
+ RUBY
169
+
170
+ # Custom view class as a spy for `#call` args
171
+ write "slices/main/views/posts/show.rb", <<~RUBY
172
+ module Main
173
+ module Views
174
+ module Posts
175
+ class Show
176
+ attr_reader :called_with
177
+
178
+ def call(**args)
179
+ @called_with = args
180
+ ""
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end
186
+ RUBY
187
+ end
188
+
189
+ context "no context class defined" do
190
+ it "defines and uses a context class" do
191
+ expect(context).to be_an_instance_of Main::Views::Context
192
+ expect(context.class).to be < Hanami::View::Context
193
+ end
194
+ end
195
+
196
+ context "context class defined" do
197
+ def before_prepare
198
+ super()
199
+
200
+ write "slices/main/views/context.rb", <<~RUBY
201
+ # auto_register: false
202
+
203
+ module Main
204
+ module Views
205
+ class Context < Hanami::View::Context
206
+ def concrete_slice_context?
207
+ true
208
+ end
209
+ end
210
+ end
211
+ end
212
+ RUBY
213
+ end
214
+
215
+ it "uses the defined context class" do
216
+ expect(context).to be_an_instance_of Main::Views::Context
217
+ expect(context).to be_a_concrete_slice_context
218
+ end
219
+ end
220
+ end
221
+ end
@@ -32,24 +32,6 @@ RSpec.describe "App action / View rendering", :app_integration do
32
32
  end
33
33
  RUBY
34
34
 
35
- write "app/views/context.rb", <<~RUBY
36
- require "hanami/view/context"
37
-
38
- module TestApp
39
- module Views
40
- class Context < Hanami::View::Context
41
- def request
42
- _options.fetch(:request)
43
- end
44
-
45
- def response
46
- _options.fetch(:response)
47
- end
48
- end
49
- end
50
- end
51
- RUBY
52
-
53
35
  write "app/actions/users/show.rb", <<~RUBY
54
36
  module TestApp
55
37
  module Actions
@@ -244,6 +244,7 @@ RSpec.describe "Hanami web app", :app_integration do
244
244
  module TestApp
245
245
  class App < Hanami::App
246
246
  config.logger.stream = File.new("/dev/null", "w")
247
+ config.render_errors = true
247
248
  end
248
249
  end
249
250
  RUBY
@@ -316,8 +317,7 @@ RSpec.describe "Hanami web app", :app_integration do
316
317
  it "excludes not found routes in root scope" do
317
318
  get "/foo"
318
319
 
319
- expect(last_response.status).to eq 404
320
- expect(last_response.body).to eq "Not Found"
320
+ expect(last_response.status).to eq 500
321
321
  expect(last_response.headers).to_not have_key("X-Auth-User-ID")
322
322
  end
323
323
 
@@ -330,12 +330,11 @@ RSpec.describe "Hanami web app", :app_integration do
330
330
  expect(last_response.headers).to have_key("X-Auth-User-ID")
331
331
  end
332
332
 
333
- it "uses Rack middleware for not found paths" do
333
+ it "does not uses the Rack middleware for not found paths" do
334
334
  get "/admin/users"
335
335
 
336
- expect(last_response.status).to be(404)
337
- expect(last_response.body).to eq "Not Found"
338
- expect(last_response.headers).to have_key("X-Auth-User-ID")
336
+ expect(last_response.status).to eq 500
337
+ expect(last_response.headers).not_to have_key("X-Auth-User-ID")
339
338
  end
340
339
  end
341
340
  end
@@ -350,6 +349,7 @@ RSpec.describe "Hanami web app", :app_integration do
350
349
  module TestApp
351
350
  class App < Hanami::App
352
351
  config.logger.stream = File.new("/dev/null", "w")
352
+ config.render_errors = true
353
353
  end
354
354
  end
355
355
  RUBY
@@ -597,15 +597,15 @@ RSpec.describe "Hanami web app", :app_integration do
597
597
  expect(last_response.headers).to_not have_key("X-API-Version")
598
598
  end
599
599
 
600
- it "uses Rack middleware for other paths" do
601
- get "/foo"
600
+ it "does not use Rack middleware for other paths" do
601
+ get "/__not_found__"
602
602
 
603
- expect(last_response.status).to be(404)
604
- expect(last_response.headers["X-Identifier-Root"]).to eq("true")
605
- expect(last_response.headers).to have_key("X-Elapsed")
606
- expect(last_response.headers).to_not have_key("X-Auth-User-ID")
607
- expect(last_response.headers).to_not have_key("X-API-Rate-Limit-Quota")
608
- expect(last_response.headers).to_not have_key("X-API-Version")
603
+ expect(last_response.status).to eq 500
604
+ expect(last_response.headers).not_to have_key("X-Identifier-Root")
605
+ expect(last_response.headers).not_to have_key("X-Elapsed")
606
+ expect(last_response.headers).not_to have_key("X-Auth-User-ID")
607
+ expect(last_response.headers).not_to have_key("X-API-Rate-Limit-Quota")
608
+ expect(last_response.headers).not_to have_key("X-API-Version")
609
609
  end
610
610
 
611
611
  context "scoped" do
@@ -621,15 +621,15 @@ RSpec.describe "Hanami web app", :app_integration do
621
621
  end
622
622
 
623
623
  it "uses Rack middleware for other paths" do
624
- get "/admin/users"
625
-
626
- expect(last_response.status).to be(404)
627
- expect(last_response.headers["X-Identifier-Admin"]).to eq("true")
628
- expect(last_response.headers).to have_key("X-Elapsed")
629
- expect(last_response.headers).to have_key("X-Elapsed")
630
- expect(last_response.headers).to have_key("X-Auth-User-ID")
631
- expect(last_response.headers).to_not have_key("X-API-Rate-Limit-Quota")
632
- expect(last_response.headers).to_not have_key("X-API-Version")
624
+ get "/admin/__not_found__"
625
+
626
+ expect(last_response.status).to eq 500
627
+ expect(last_response.headers).not_to have_key("X-Identifier-Admin")
628
+ expect(last_response.headers).not_to have_key("X-Elapsed")
629
+ expect(last_response.headers).not_to have_key("X-Elapsed")
630
+ expect(last_response.headers).not_to have_key("X-Auth-User-ID")
631
+ expect(last_response.headers).not_to have_key("X-API-Rate-Limit-Quota")
632
+ expect(last_response.headers).not_to have_key("X-API-Version")
633
633
  end
634
634
 
635
635
  # See: https://github.com/hanami/api/issues/8
@@ -210,10 +210,11 @@ RSpec.describe "Hanami web app", :app_integration do
210
210
  let(:app) { Main::Slice.rack_app }
211
211
 
212
212
  around do |example|
213
+ @prev_hanami_env = ENV["HANAMI_ENV"]
213
214
  ENV["HANAMI_ENV"] = "production"
214
215
  example.run
215
216
  ensure
216
- ENV["HANAMI_ENV"] = "test"
217
+ ENV["HANAMI_ENV"] = @prev_hanami_env
217
218
  end
218
219
 
219
220
  specify "Has rack monitor preconfigured with default request logging (when used via a slice)" do
@@ -569,6 +570,7 @@ RSpec.describe "Hanami web app", :app_integration do
569
570
 
570
571
  module TestApp
571
572
  class App < Hanami::App
573
+ config.render_detailed_errors = false
572
574
  end
573
575
  end
574
576
  RUBY
@@ -600,6 +602,8 @@ RSpec.describe "Hanami web app", :app_integration do
600
602
 
601
603
  module TestApp
602
604
  class App < Hanami::App
605
+ config.render_detailed_errors = false
606
+
603
607
  register_slice :admin
604
608
  end
605
609
  end
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe "App view / Config / Default context", :app_integration do
4
+ before do
5
+ with_directory(@dir = make_tmp_directory) do
6
+ write "config/app.rb", <<~RUBY
7
+ module TestApp
8
+ class App < Hanami::App
9
+ end
10
+ end
11
+ RUBY
12
+
13
+ write "app/view.rb", <<~RUBY
14
+ # auto_register: false
15
+
16
+ require "hanami/view"
17
+
18
+ module TestApp
19
+ class View < Hanami::View
20
+ end
21
+ end
22
+ RUBY
23
+
24
+ before_prepare if respond_to?(:before_prepare)
25
+ require "hanami/prepare"
26
+ end
27
+ end
28
+
29
+ subject(:default_context) { view_class.config.default_context }
30
+
31
+ describe "app view" do
32
+ let(:view_class) { TestApp::View }
33
+
34
+ describe "no concrete context class defined" do
35
+ it "generates an app context class and configures it as the view's default_context" do
36
+ expect(default_context).to be_an_instance_of TestApp::Views::Context
37
+ expect(default_context.class.superclass).to be Hanami::View::Context
38
+ end
39
+ end
40
+
41
+ describe "concrete context class defined" do
42
+ def before_prepare
43
+ write "app/views/context.rb", <<~RUBY
44
+ # auto_register: false
45
+
46
+ module TestApp
47
+ module Views
48
+ class Context < Hanami::View::Context
49
+ def concrete?
50
+ true
51
+ end
52
+ end
53
+ end
54
+ end
55
+ RUBY
56
+ end
57
+
58
+ it "configures the app scope class as the view's scope_class" do
59
+ expect(default_context).to be_an_instance_of TestApp::Views::Context
60
+ expect(default_context).to be_concrete
61
+ end
62
+ end
63
+ end
64
+
65
+ describe "slice view" do
66
+ let(:view_class) { Main::View }
67
+
68
+ def before_prepare
69
+ write "slices/main/view.rb", <<~RUBY
70
+ # auto_register: false
71
+
72
+ module Main
73
+ class View < TestApp::View
74
+ end
75
+ end
76
+ RUBY
77
+ end
78
+
79
+ describe "no concrete slice context class defined" do
80
+ it "generates an app context class and configures it as the view's default_context" do
81
+ expect(default_context).to be_an_instance_of Main::Views::Context
82
+ expect(default_context.class.superclass).to be TestApp::Views::Context
83
+ end
84
+ end
85
+
86
+ describe "concrete slice context class defined" do
87
+ def before_prepare
88
+ super
89
+
90
+ write "slices/main/views/context.rb", <<~RUBY
91
+ # auto_register: false
92
+
93
+ module Main
94
+ module Views
95
+ class Context < Hanami::View::Context
96
+ def concrete?
97
+ true
98
+ end
99
+ end
100
+ end
101
+ end
102
+ RUBY
103
+ end
104
+
105
+ it "configures the slice context as the view's default_context" do
106
+ expect(default_context).to be_an_instance_of Main::Views::Context
107
+ expect(default_context).to be_concrete
108
+ end
109
+ end
110
+
111
+ describe "view not inheriting from app view, no concrete context class defined" do
112
+ def before_prepare
113
+ write "slices/main/view.rb", <<~RUBY
114
+ # auto_register: false
115
+
116
+ module Main
117
+ class View < Hanami::View
118
+ end
119
+ end
120
+ RUBY
121
+ end
122
+
123
+ it "generates a slice context class, inheriting from the app context class, and configures it as the view's default_context" do
124
+ expect(default_context).to be_an_instance_of Main::Views::Context
125
+ expect(default_context.class.superclass).to be TestApp::Views::Context
126
+ end
127
+ end
128
+
129
+ describe "no app view class defined" do
130
+ def before_prepare
131
+ FileUtils.rm "app/view.rb"
132
+
133
+ write "slices/main/view.rb", <<~RUBY
134
+ # auto_register: false
135
+
136
+ module Main
137
+ class View < Hanami::View
138
+ end
139
+ end
140
+ RUBY
141
+ end
142
+
143
+ it "generates a slice context class, inheriting from the app context class, and configures it as the view's default_context" do
144
+ expect(default_context).to be_an_instance_of Main::Views::Context
145
+ expect(default_context.class.superclass).to be Hanami::View::Context
146
+ end
147
+ end
148
+ end
149
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require "hanami"
4
4
 
5
- RSpec.describe "App view / Inflector", :app_integration do
5
+ RSpec.describe "App view / Config / Inflector", :app_integration do
6
6
  before do
7
7
  module TestApp
8
8
  class App < Hanami::App
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe "App view / Config / Part class", :app_integration do
4
+ before do
5
+ with_directory(make_tmp_directory) do
6
+ write "config/app.rb", <<~RUBY
7
+ module TestApp
8
+ class App < Hanami::App
9
+ end
10
+ end
11
+ RUBY
12
+
13
+ write "app/view.rb", <<~RUBY
14
+ # auto_register: false
15
+
16
+ require "hanami/view"
17
+
18
+ module TestApp
19
+ class View < Hanami::View
20
+ end
21
+ end
22
+ RUBY
23
+
24
+ before_prepare if respond_to?(:before_prepare)
25
+ require "hanami/prepare"
26
+ end
27
+ end
28
+
29
+ describe "app view" do
30
+ let(:view_class) { TestApp::View }
31
+
32
+ context "no concrete app part class defined" do
33
+ it "generates an app part class and configures it as the view's part_class" do
34
+ expect(view_class.config.part_class).to be TestApp::Views::Part
35
+ expect(view_class.config.part_class.superclass).to be Hanami::View::Part
36
+ end
37
+ end
38
+
39
+ context "concrete app part class defined" do
40
+ def before_prepare
41
+ write "app/views/part.rb", <<~RUBY
42
+ # auto_register: false
43
+
44
+ module TestApp
45
+ module Views
46
+ class Part < Hanami::View::Part
47
+ def self.concrete?
48
+ true
49
+ end
50
+ end
51
+ end
52
+ end
53
+ RUBY
54
+ end
55
+
56
+ it "configures the app part class as the view's part_class" do
57
+ expect(view_class.config.part_class).to be TestApp::Views::Part
58
+ expect(view_class.config.part_class).to be_concrete
59
+ end
60
+ end
61
+ end
62
+
63
+ describe "slice view" do
64
+ let(:view_class) { Main::View }
65
+
66
+ def before_prepare
67
+ write "slices/main/view.rb", <<~RUBY
68
+ # auto_register: false
69
+
70
+ module Main
71
+ class View < TestApp::View
72
+ end
73
+ end
74
+ RUBY
75
+ end
76
+
77
+ context "no concrete slice part class defined" do
78
+ it "generates a slice part class, inheriting from the app part class, and configures it as the view's part_class" do
79
+ expect(view_class.config.part_class).to be Main::Views::Part
80
+ expect(view_class.config.part_class.superclass).to be TestApp::Views::Part
81
+ end
82
+ end
83
+
84
+ context "concrete slice part class defined" do
85
+ def before_prepare
86
+ super
87
+
88
+ write "slices/main/views/part.rb", <<~RUBY
89
+ # auto_register: false
90
+
91
+ module Main
92
+ module Views
93
+ class Part < TestApp::Views::Part
94
+ def self.concrete?
95
+ true
96
+ end
97
+ end
98
+ end
99
+ end
100
+ RUBY
101
+ end
102
+
103
+ it "configures the slice part class as the view's part_class" do
104
+ expect(view_class.config.part_class).to be Main::Views::Part
105
+ expect(view_class.config.part_class).to be_concrete
106
+ end
107
+ end
108
+
109
+ context "view not inheriting from app view, no concrete part class" do
110
+ def before_prepare
111
+ write "slices/main/view.rb", <<~RUBY
112
+ # auto_register: false
113
+
114
+ module Main
115
+ class View < Hanami::View
116
+ end
117
+ end
118
+ RUBY
119
+ end
120
+
121
+ it "generates a slice part class, inheriting from the app part class, and configures it as the view's part_class" do
122
+ expect(view_class.config.part_class).to be Main::Views::Part
123
+ expect(view_class.config.part_class.superclass).to be TestApp::Views::Part
124
+ end
125
+ end
126
+
127
+ context "no app view class defined" do
128
+ def before_prepare
129
+ FileUtils.rm "app/view.rb"
130
+
131
+ write "slices/main/view.rb", <<~RUBY
132
+ # auto_register: false
133
+
134
+ module Main
135
+ class View < Hanami::View
136
+ end
137
+ end
138
+ RUBY
139
+ end
140
+
141
+ it "generates a slice part class, inheriting from Hanami::View::Part, and configures it as the view's part_class" do
142
+ expect(view_class.config.part_class).to be Main::Views::Part
143
+ expect(view_class.config.part_class.superclass).to be Hanami::View::Part
144
+ end
145
+ end
146
+ end
147
+ end