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,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ostruct"
4
+
5
+ # rubocop:disable Style/OpenStructUse
6
+
7
+ RSpec.describe "App view / Helpers / Part helpers", :app_integration do
8
+ before do
9
+ with_directory(make_tmp_directory) do
10
+ write "config/app.rb", <<~RUBY
11
+ module TestApp
12
+ class App < Hanami::App
13
+ end
14
+ end
15
+ RUBY
16
+
17
+ write "app/view.rb", <<~RUBY
18
+ # auto_register: false
19
+
20
+ require "hanami/view"
21
+
22
+ module TestApp
23
+ class View < Hanami::View
24
+ config.layout = nil
25
+ end
26
+ end
27
+ RUBY
28
+
29
+ before_prepare if respond_to?(:before_prepare)
30
+ require "hanami/prepare"
31
+ end
32
+ end
33
+
34
+ describe "app view and parts" do
35
+ def before_prepare
36
+ write "app/views/posts/show.rb", <<~RUBY
37
+ module TestApp
38
+ module Views
39
+ module Posts
40
+ class Show < TestApp::View
41
+ expose :post
42
+ end
43
+ end
44
+ end
45
+ end
46
+ RUBY
47
+
48
+ write "app/views/parts/post.rb", <<~RUBY
49
+ module TestApp
50
+ module Views
51
+ module Parts
52
+ class Post < TestApp::Views::Part
53
+ def number
54
+ format_number(value.number)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ RUBY
61
+
62
+ write "app/templates/posts/show.html.erb", <<~ERB
63
+ <h1><%= post.number %></h1>
64
+ ERB
65
+ end
66
+
67
+ it "makes default helpers available in parts" do
68
+ post = OpenStruct.new(number: 12_345)
69
+ output = TestApp::App["views.posts.show"].call(post: post).to_s.strip
70
+
71
+ expect(output).to eq "<h1>12,345</h1>"
72
+ end
73
+ end
74
+
75
+ describe "slice view and parts" do
76
+ def before_prepare
77
+ write "slices/main/view.rb", <<~RUBY
78
+ module Main
79
+ class View < TestApp::View
80
+ end
81
+ end
82
+ RUBY
83
+
84
+ write "slices/main/views/posts/show.rb", <<~RUBY
85
+ module Main
86
+ module Views
87
+ module Posts
88
+ class Show < Main::View
89
+ expose :post
90
+ end
91
+ end
92
+ end
93
+ end
94
+ RUBY
95
+
96
+ write "slices/main/views/parts/post.rb", <<~RUBY
97
+ module Main
98
+ module Views
99
+ module Parts
100
+ class Post < Main::Views::Part
101
+ def number
102
+ format_number(value.number)
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+ RUBY
109
+
110
+ write "slices/main/templates/posts/show.html.erb", <<~ERB
111
+ <h1><%= post.number %></h1>
112
+ ERB
113
+ end
114
+
115
+ it "makes default helpers available in parts" do
116
+ post = OpenStruct.new(number: 12_345)
117
+ output = Main::Slice["views.posts.show"].call(post: post).to_s.strip
118
+
119
+ expect(output).to eq "<h1>12,345</h1>"
120
+ end
121
+ end
122
+ end
123
+
124
+ # rubocop:enable Style/OpenStructUse
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe "App view / Helpers / Scope helpers", :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
+ config.layout = nil
21
+ end
22
+ end
23
+ RUBY
24
+
25
+ before_prepare if respond_to?(:before_prepare)
26
+ require "hanami/prepare"
27
+ end
28
+ end
29
+
30
+ describe "app view" do
31
+ def before_prepare
32
+ write "app/views/posts/show.rb", <<~RUBY
33
+ module TestApp
34
+ module Views
35
+ module Posts
36
+ class Show < TestApp::View
37
+ end
38
+ end
39
+ end
40
+ end
41
+ RUBY
42
+
43
+ write "app/templates/posts/show.html.erb", <<~ERB
44
+ <h1><%= format_number(12_345) %></h1>
45
+ ERB
46
+ end
47
+
48
+ it "makes default helpers available in templates" do
49
+ output = TestApp::App["views.posts.show"].call.to_s.strip
50
+ expect(output).to eq "<h1>12,345</h1>"
51
+ end
52
+ end
53
+
54
+ describe "slice view" do
55
+ def before_prepare
56
+ write "slices/main/view.rb", <<~RUBY
57
+ module Main
58
+ class View < TestApp::View
59
+ end
60
+ end
61
+ RUBY
62
+
63
+ write "slices/main/views/posts/show.rb", <<~RUBY
64
+ module Main
65
+ module Views
66
+ module Posts
67
+ class Show < Main::View
68
+ end
69
+ end
70
+ end
71
+ end
72
+ RUBY
73
+
74
+ write "slices/main/templates/posts/show.html.erb", <<~ERB
75
+ <h1><%= format_number(12_345) %></h1>
76
+ ERB
77
+ end
78
+
79
+ it "makes default helpers available in templates" do
80
+ output = Main::Slice["views.posts.show"].call.to_s.strip
81
+ expect(output).to eq "<h1>12,345</h1>"
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,162 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ostruct"
4
+
5
+ # rubocop:disable Style/OpenStructUse
6
+
7
+ RSpec.describe "App view / Helpers / User-defined helpers / Scope helpers", :app_integration do
8
+ before do
9
+ with_directory(make_tmp_directory) do
10
+ write "config/app.rb", <<~RUBY
11
+ module TestApp
12
+ class App < Hanami::App
13
+ end
14
+ end
15
+ RUBY
16
+
17
+ write "app/view.rb", <<~RUBY
18
+ # auto_register: false
19
+
20
+ require "hanami/view"
21
+
22
+ module TestApp
23
+ class View < Hanami::View
24
+ config.layout = nil
25
+ end
26
+ end
27
+ RUBY
28
+
29
+ write "app/views/helpers.rb", <<~'RUBY'
30
+ # auto_register: false
31
+
32
+ module TestApp
33
+ module Views
34
+ module Helpers
35
+ def exclaim_from_app(str)
36
+ tag.h1("#{str}! (app helper)")
37
+ end
38
+ end
39
+ end
40
+ end
41
+ RUBY
42
+
43
+ before_prepare if respond_to?(:before_prepare)
44
+ require "hanami/prepare"
45
+ end
46
+ end
47
+
48
+ describe "app view and parts" do
49
+ def before_prepare
50
+ write "app/views/posts/show.rb", <<~RUBY
51
+ module TestApp
52
+ module Views
53
+ module Posts
54
+ class Show < TestApp::View
55
+ expose :post
56
+ end
57
+ end
58
+ end
59
+ end
60
+ RUBY
61
+
62
+ write "app/views/parts/post.rb", <<~RUBY
63
+ module TestApp
64
+ module Views
65
+ module Parts
66
+ class Post < TestApp::Views::Part
67
+ def title
68
+ exclaim_from_app(value.title)
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ RUBY
75
+
76
+ write "app/templates/posts/show.html.erb", <<~ERB
77
+ <%= post.title %>
78
+ ERB
79
+ end
80
+
81
+ it "makes user-defined helpers available in parts" do
82
+ post = OpenStruct.new(title: "Hello world")
83
+ output = TestApp::App["views.posts.show"].call(post: post).to_s.strip
84
+
85
+ expect(output).to eq "<h1>Hello world! (app helper)</h1>"
86
+ end
87
+ end
88
+
89
+ describe "slice view and parts" do
90
+ def before_prepare
91
+ write "slices/main/view.rb", <<~RUBY
92
+ module Main
93
+ class View < TestApp::View
94
+ # FIXME: base slice views should override paths from the base app view
95
+ config.paths = [File.join(File.expand_path(__dir__), "templates")]
96
+ end
97
+ end
98
+ RUBY
99
+
100
+ write "slices/main/views/helpers.rb", <<~'RUBY'
101
+ # auto_register: false
102
+
103
+ module Main
104
+ module Views
105
+ module Helpers
106
+ def exclaim_from_slice(str)
107
+ tag.h1("#{str}! (slice helper)")
108
+ end
109
+ end
110
+ end
111
+ end
112
+ RUBY
113
+
114
+ write "slices/main/views/posts/show.rb", <<~RUBY
115
+ module Main
116
+ module Views
117
+ module Posts
118
+ class Show < Main::View
119
+ expose :post
120
+ end
121
+ end
122
+ end
123
+ end
124
+ RUBY
125
+
126
+ write "slices/main/views/parts/post.rb", <<~RUBY
127
+ module Main
128
+ module Views
129
+ module Parts
130
+ class Post < Main::Views::Part
131
+ def title
132
+ exclaim_from_slice(value.title)
133
+ end
134
+
135
+ def title_from_app
136
+ exclaim_from_app(value.title)
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
142
+ RUBY
143
+
144
+ write "slices/main/templates/posts/show.html.erb", <<~ERB
145
+ <%= post.title %>
146
+ <%= post.title_from_app %>
147
+ ERB
148
+ end
149
+
150
+ it "makes user-defined helpers (from app as well as slice) available in parts" do
151
+ post = OpenStruct.new(title: "Hello world")
152
+ output = Main::Slice["views.posts.show"].call(post: post).to_s
153
+
154
+ expect(output).to eq <<~HTML
155
+ <h1>Hello world! (slice helper)</h1>
156
+ <h1>Hello world! (app helper)</h1>
157
+ HTML
158
+ end
159
+ end
160
+ end
161
+
162
+ # rubocop:enable Style/OpenStructUse
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe "App view / Helpers / User-defined helpers / Scope helpers", :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
+ config.layout = nil
21
+ end
22
+ end
23
+ RUBY
24
+
25
+ write "app/views/helpers.rb", <<~'RUBY'
26
+ # auto_register: false
27
+
28
+ module TestApp
29
+ module Views
30
+ module Helpers
31
+ def exclaim_from_app(str)
32
+ tag.h1("#{str}! (app helper)")
33
+ end
34
+ end
35
+ end
36
+ end
37
+ RUBY
38
+
39
+ before_prepare if respond_to?(:before_prepare)
40
+ require "hanami/prepare"
41
+ end
42
+ end
43
+
44
+ describe "app view" do
45
+ def before_prepare
46
+ write "app/views/posts/show.rb", <<~RUBY
47
+ module TestApp
48
+ module Views
49
+ module Posts
50
+ class Show < TestApp::View
51
+ end
52
+ end
53
+ end
54
+ end
55
+ RUBY
56
+
57
+ write "app/templates/posts/show.html.erb", <<~ERB
58
+ <%= exclaim_from_app("Hello world") %>
59
+ ERB
60
+ end
61
+
62
+ it "makes user-defined helpers available in templates" do
63
+ output = TestApp::App["views.posts.show"].call.to_s.strip
64
+ expect(output).to eq "<h1>Hello world! (app helper)</h1>"
65
+ end
66
+ end
67
+
68
+ describe "slice view" do
69
+ def before_prepare
70
+ write "slices/main/view.rb", <<~RUBY
71
+ module Main
72
+ class View < TestApp::View
73
+ # FIXME: base slice views should override paths from the base app view
74
+ config.paths = [File.join(File.expand_path(__dir__), "templates")]
75
+ end
76
+ end
77
+ RUBY
78
+
79
+ write "slices/main/views/helpers.rb", <<~'RUBY'
80
+ # auto_register: false
81
+
82
+ module Main
83
+ module Views
84
+ module Helpers
85
+ def exclaim_from_slice(str)
86
+ tag.h1("#{str}! (slice helper)")
87
+ end
88
+ end
89
+ end
90
+ end
91
+ RUBY
92
+
93
+ write "slices/main/views/posts/show.rb", <<~RUBY
94
+ module Main
95
+ module Views
96
+ module Posts
97
+ class Show < Main::View
98
+ end
99
+ end
100
+ end
101
+ end
102
+ RUBY
103
+
104
+ write "slices/main/templates/posts/show.html.erb", <<~ERB
105
+ <%= exclaim_from_slice("Hello world") %>
106
+ <%= exclaim_from_app("Hello world") %>
107
+ ERB
108
+ end
109
+
110
+ it "makes user-defined helpers (from app as well as slice) available in templates" do
111
+ output = Main::Slice["views.posts.show"].call.to_s
112
+
113
+ expect(output).to eq <<~HTML
114
+ <h1>Hello world! (slice helper)</h1>
115
+ <h1>Hello world! (app helper)</h1>
116
+ HTML
117
+ end
118
+ end
119
+ end
@@ -3,7 +3,7 @@
3
3
  RSpec.describe "App view / Slice configuration", :app_integration do
4
4
  before do
5
5
  with_directory(@dir = make_tmp_directory) do
6
- write "config/app.rb", <<~'RUBY'
6
+ write "config/app.rb", <<~RUBY
7
7
  require "hanami"
8
8
 
9
9
  module TestApp
@@ -12,7 +12,7 @@ RSpec.describe "App view / Slice configuration", :app_integration do
12
12
  end
13
13
  RUBY
14
14
 
15
- write "app/view.rb", <<~'RUBY'
15
+ write "app/view.rb", <<~RUBY
16
16
  require "hanami/view"
17
17
 
18
18
  module TestApp
@@ -60,7 +60,7 @@ RSpec.describe "App view / Slice configuration", :app_integration do
60
60
  describe "subclass in app" do
61
61
  before do
62
62
  with_directory(@dir) do
63
- write "app/views/articles/index.rb", <<~'RUBY'
63
+ write "app/views/articles/index.rb", <<~RUBY
64
64
  module TestApp
65
65
  module Views
66
66
  module Articles
@@ -100,7 +100,7 @@ RSpec.describe "App view / Slice configuration", :app_integration do
100
100
  describe "subclass in slice" do
101
101
  before do
102
102
  with_directory(@dir) do
103
- write "slices/admin/views/articles/index.rb", <<~'RUBY'
103
+ write "slices/admin/views/articles/index.rb", <<~RUBY
104
104
  module Admin
105
105
  module Views
106
106
  module Articles
@@ -141,7 +141,7 @@ RSpec.describe "App view / Slice configuration", :app_integration do
141
141
  describe "inheriting from a slice-level base class, in turn inheriting from an app-level base class" do
142
142
  before do
143
143
  with_directory(@dir) do
144
- write "slices/admin/view.rb", <<~'RUBY'
144
+ write "slices/admin/view.rb", <<~RUBY
145
145
  module Admin
146
146
  class View < TestApp::View
147
147
  end
@@ -177,7 +177,7 @@ RSpec.describe "App view / Slice configuration", :app_integration do
177
177
  context "slice views config present" do
178
178
  before do
179
179
  with_directory(@dir) do
180
- write "config/slices/admin.rb", <<~'RUBY'
180
+ write "config/slices/admin.rb", <<~RUBY
181
181
  module Admin
182
182
  class Slice < Hanami::Slice
183
183
  config.views.layout = "slice_layout"
@@ -215,7 +215,7 @@ RSpec.describe "App view / Slice configuration", :app_integration do
215
215
  describe "subclass in slice" do
216
216
  before do
217
217
  with_directory(@dir) do
218
- write "slices/admin/views/articles/index.rb", <<~'RUBY'
218
+ write "slices/admin/views/articles/index.rb", <<~RUBY
219
219
  module Admin
220
220
  module Views
221
221
  module Articles
@@ -245,7 +245,7 @@ RSpec.describe "App view / Slice configuration", :app_integration do
245
245
 
246
246
  it "applies views config from the slice" do
247
247
  with_directory(@dir) do
248
- write "config/slices/admin.rb", <<~'RUBY'
248
+ write "config/slices/admin.rb", <<~RUBY
249
249
  module Admin
250
250
  class Slice < Hanami::Slice
251
251
  config.views.layout = "slice_layout"
@@ -269,7 +269,7 @@ RSpec.describe "App view / Slice configuration", :app_integration do
269
269
 
270
270
  it "prefers config from the slice base class over views config from the slice" do
271
271
  with_directory(@dir) do
272
- write "config/slices/admin.rb", <<~'RUBY'
272
+ write "config/slices/admin.rb", <<~RUBY
273
273
  module Admin
274
274
  class Slice < Hanami::Slice
275
275
  config.views.layout = "slice_layout"
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "rack/test"
5
+
6
+ RSpec.describe "Web / Rendering detailed errors", :app_integration do
7
+ include Rack::Test::Methods
8
+
9
+ let(:app) { Hanami.app }
10
+
11
+ before do
12
+ with_directory(@dir = make_tmp_directory) do
13
+ write "config/app.rb", <<~RUBY
14
+ require "hanami"
15
+
16
+ module TestApp
17
+ class App < Hanami::App
18
+ config.logger.stream = File.new("/dev/null", "w")
19
+ config.render_detailed_errors = true
20
+ end
21
+ end
22
+ RUBY
23
+
24
+ write "config/routes.rb", <<~RUBY
25
+ module TestApp
26
+ class Routes < Hanami::Routes
27
+ get "error", to: "error"
28
+ end
29
+ end
30
+ RUBY
31
+
32
+ write "app/actions/error.rb", <<~RUBY
33
+ module TestApp
34
+ module Actions
35
+ class Error < Hanami::Action
36
+ def handle(*)
37
+ raise "oops"
38
+ end
39
+ end
40
+ end
41
+ end
42
+ RUBY
43
+
44
+ before_prepare if respond_to?(:before_prepare)
45
+ require "hanami/prepare"
46
+ end
47
+ end
48
+
49
+ describe "HTML request" do
50
+ it "renders a detailed HTML error page" do
51
+ get "/error", {}, "HTTP_ACCEPT" => "text/html"
52
+
53
+ expect(last_response.status).to eq 500
54
+
55
+ html = Capybara.string(last_response.body)
56
+ expect(html).to have_selector("header", text: "RuntimeError at /error")
57
+ expect(html).to have_selector("ul.frames li.application", text: "app/actions/error.rb")
58
+ end
59
+ end
60
+
61
+ describe "Other request types" do
62
+ it "renders a detailed error page in text" do
63
+ get "/error", {}, "HTTP_ACCEPT" => "application/json"
64
+
65
+ expect(last_response.status).to eq 500
66
+
67
+ expect(last_response.body).to include "RuntimeError at /error"
68
+ expect(last_response.body).to match %r{App backtrace.+app/actions/error.rb}m
69
+ end
70
+ end
71
+
72
+ describe "render_detailed_errors config disabled" do
73
+ def before_prepare
74
+ write "config/app.rb", <<~RUBY
75
+ require "hanami"
76
+
77
+ module TestApp
78
+ class App < Hanami::App
79
+ config.logger.stream = File.new("/dev/null", "w")
80
+ config.render_detailed_errors = false
81
+ end
82
+ end
83
+ RUBY
84
+ end
85
+
86
+ it "raises errors from within the app" do
87
+ expect { get "/error" }.to raise_error(RuntimeError, "oops")
88
+ end
89
+ end
90
+ end