hanami 2.0.0.alpha8 → 2.0.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 (224) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +442 -241
  3. data/FEATURES.md +30 -9
  4. data/README.md +1 -3
  5. data/hanami.gemspec +21 -11
  6. data/lib/hanami/app.rb +141 -0
  7. data/lib/hanami/assets/application_configuration.rb +10 -4
  8. data/lib/hanami/configuration/actions/content_security_policy.rb +5 -5
  9. data/lib/hanami/configuration/actions/cookies.rb +2 -2
  10. data/lib/hanami/configuration/actions.rb +10 -4
  11. data/lib/hanami/configuration/logger.rb +4 -4
  12. data/lib/hanami/configuration/router.rb +2 -6
  13. data/lib/hanami/configuration/sessions.rb +1 -1
  14. data/lib/hanami/configuration/views.rb +9 -4
  15. data/lib/hanami/configuration.rb +118 -46
  16. data/lib/hanami/constants.rb +24 -2
  17. data/lib/hanami/errors.rb +1 -1
  18. data/lib/hanami/{application → extensions}/action/slice_configured_action.rb +9 -9
  19. data/lib/hanami/extensions/action.rb +79 -0
  20. data/lib/hanami/extensions/view/context.rb +106 -0
  21. data/lib/hanami/{application → extensions}/view/slice_configured_context.rb +10 -10
  22. data/lib/hanami/{application → extensions}/view/slice_configured_view.rb +12 -6
  23. data/lib/hanami/extensions/view.rb +33 -0
  24. data/lib/hanami/extensions.rb +10 -0
  25. data/lib/hanami/providers/inflector.rb +13 -0
  26. data/lib/hanami/providers/logger.rb +13 -0
  27. data/lib/hanami/providers/rack.rb +27 -0
  28. data/lib/hanami/providers/routes.rb +33 -0
  29. data/lib/hanami/providers/settings.rb +23 -0
  30. data/lib/hanami/rake_tasks.rb +61 -0
  31. data/lib/hanami/routes.rb +51 -0
  32. data/lib/hanami/server.rb +1 -1
  33. data/lib/hanami/settings/dotenv_store.rb +58 -0
  34. data/lib/hanami/settings.rb +90 -0
  35. data/lib/hanami/setup.rb +4 -2
  36. data/lib/hanami/{application → slice}/router.rb +18 -13
  37. data/lib/hanami/slice/routes_helper.rb +37 -0
  38. data/lib/hanami/{application → slice}/routing/middleware/stack.rb +43 -5
  39. data/lib/hanami/slice/routing/resolver.rb +97 -0
  40. data/lib/hanami/{application → slice}/view_name_inferrer.rb +3 -3
  41. data/lib/hanami/slice.rb +246 -73
  42. data/lib/hanami/slice_configurable.rb +4 -17
  43. data/lib/hanami/slice_name.rb +6 -6
  44. data/lib/hanami/slice_registrar.rb +119 -0
  45. data/lib/hanami/version.rb +1 -1
  46. data/lib/hanami/web/rack_logger.rb +1 -1
  47. data/lib/hanami.rb +34 -26
  48. data/spec/integration/application_middleware_stack_spec.rb +84 -0
  49. data/spec/integration/assets/cdn_spec.rb +48 -0
  50. data/spec/integration/assets/fingerprint_spec.rb +42 -0
  51. data/spec/integration/assets/helpers_spec.rb +50 -0
  52. data/spec/integration/assets/serve_spec.rb +70 -0
  53. data/spec/integration/assets/subresource_integrity_spec.rb +54 -0
  54. data/spec/integration/body_parsers_spec.rb +50 -0
  55. data/spec/integration/cli/assets/precompile_spec.rb +147 -0
  56. data/spec/integration/cli/assets_spec.rb +14 -0
  57. data/spec/integration/cli/console_spec.rb +105 -0
  58. data/spec/integration/cli/db/apply_spec.rb +74 -0
  59. data/spec/integration/cli/db/console_spec.rb +40 -0
  60. data/spec/integration/cli/db/create_spec.rb +50 -0
  61. data/spec/integration/cli/db/drop_spec.rb +54 -0
  62. data/spec/integration/cli/db/migrate_spec.rb +108 -0
  63. data/spec/integration/cli/db/prepare_spec.rb +36 -0
  64. data/spec/integration/cli/db/rollback_spec.rb +96 -0
  65. data/spec/integration/cli/db/version_spec.rb +38 -0
  66. data/spec/integration/cli/db_spec.rb +21 -0
  67. data/spec/integration/cli/destroy/action_spec.rb +143 -0
  68. data/spec/integration/cli/destroy/app_spec.rb +118 -0
  69. data/spec/integration/cli/destroy/mailer_spec.rb +74 -0
  70. data/spec/integration/cli/destroy/migration_spec.rb +70 -0
  71. data/spec/integration/cli/destroy/model_spec.rb +113 -0
  72. data/spec/integration/cli/destroy_spec.rb +18 -0
  73. data/spec/integration/cli/generate/action_spec.rb +469 -0
  74. data/spec/integration/cli/generate/app_spec.rb +215 -0
  75. data/spec/integration/cli/generate/mailer_spec.rb +189 -0
  76. data/spec/integration/cli/generate/migration_spec.rb +72 -0
  77. data/spec/integration/cli/generate/model_spec.rb +290 -0
  78. data/spec/integration/cli/generate/secret_spec.rb +56 -0
  79. data/spec/integration/cli/generate_spec.rb +19 -0
  80. data/spec/integration/cli/new/database_spec.rb +235 -0
  81. data/spec/integration/cli/new/hanami_head_spec.rb +27 -0
  82. data/spec/integration/cli/new/template_spec.rb +118 -0
  83. data/spec/integration/cli/new/test_spec.rb +274 -0
  84. data/spec/integration/cli/new_spec.rb +970 -0
  85. data/spec/integration/cli/plugins_spec.rb +39 -0
  86. data/spec/integration/cli/routes_spec.rb +49 -0
  87. data/spec/integration/cli/server_spec.rb +626 -0
  88. data/spec/integration/cli/version_spec.rb +85 -0
  89. data/spec/integration/early_hints_spec.rb +35 -0
  90. data/spec/integration/handle_exceptions_spec.rb +244 -0
  91. data/spec/integration/head_spec.rb +89 -0
  92. data/spec/integration/http_headers_spec.rb +29 -0
  93. data/spec/integration/mailer_spec.rb +32 -0
  94. data/spec/integration/middleware_spec.rb +81 -0
  95. data/spec/integration/mount_applications_spec.rb +88 -0
  96. data/spec/integration/project_initializers_spec.rb +40 -0
  97. data/spec/integration/rackup_spec.rb +35 -0
  98. data/spec/integration/rake/with_minitest_spec.rb +67 -0
  99. data/spec/integration/rake/with_rspec_spec.rb +69 -0
  100. data/spec/integration/routing_helpers_spec.rb +61 -0
  101. data/spec/integration/security/content_security_policy_spec.rb +46 -0
  102. data/spec/integration/security/csrf_protection_spec.rb +42 -0
  103. data/spec/integration/security/force_ssl_spec.rb +29 -0
  104. data/spec/integration/security/x_content_type_options_spec.rb +46 -0
  105. data/spec/integration/security/x_frame_options_spec.rb +46 -0
  106. data/spec/integration/security/x_xss_protection_spec.rb +46 -0
  107. data/spec/integration/send_file_spec.rb +51 -0
  108. data/spec/integration/sessions_spec.rb +247 -0
  109. data/spec/integration/static_middleware_spec.rb +21 -0
  110. data/spec/integration/streaming_spec.rb +41 -0
  111. data/spec/integration/unsafe_send_file_spec.rb +52 -0
  112. data/spec/isolation/hanami/application/already_configured_spec.rb +19 -0
  113. data/spec/isolation/hanami/application/inherit_anonymous_class_spec.rb +10 -0
  114. data/spec/isolation/hanami/application/inherit_concrete_class_spec.rb +14 -0
  115. data/spec/isolation/hanami/application/not_configured_spec.rb +9 -0
  116. data/spec/isolation/hanami/application/routes/configured_spec.rb +44 -0
  117. data/spec/isolation/hanami/application/routes/not_configured_spec.rb +16 -0
  118. data/spec/isolation/hanami/boot/success_spec.rb +50 -0
  119. data/spec/new_integration/action/configuration_spec.rb +26 -0
  120. data/spec/new_integration/action/cookies_spec.rb +58 -0
  121. data/spec/new_integration/action/csrf_protection_spec.rb +54 -0
  122. data/spec/new_integration/action/routes_spec.rb +73 -0
  123. data/spec/new_integration/action/sessions_spec.rb +50 -0
  124. data/spec/new_integration/action/view_integration_spec.rb +165 -0
  125. data/spec/new_integration/action/view_rendering/automatic_rendering_spec.rb +247 -0
  126. data/spec/new_integration/action/view_rendering/paired_view_inference_spec.rb +115 -0
  127. data/spec/new_integration/action/view_rendering_spec.rb +107 -0
  128. data/spec/new_integration/code_loading/loading_from_app_spec.rb +152 -0
  129. data/spec/new_integration/code_loading/loading_from_slice_spec.rb +165 -0
  130. data/spec/new_integration/container/application_routes_helper_spec.rb +48 -0
  131. data/spec/new_integration/container/auto_injection_spec.rb +53 -0
  132. data/spec/new_integration/container/auto_registration_spec.rb +86 -0
  133. data/spec/new_integration/container/autoloader_spec.rb +80 -0
  134. data/spec/new_integration/container/imports_spec.rb +253 -0
  135. data/spec/new_integration/container/prepare_container_spec.rb +123 -0
  136. data/spec/new_integration/container/shutdown_spec.rb +91 -0
  137. data/spec/new_integration/container/standard_bootable_components_spec.rb +124 -0
  138. data/spec/new_integration/rack_app/middleware_spec.rb +215 -0
  139. data/spec/new_integration/rack_app/non_booted_rack_app_spec.rb +105 -0
  140. data/spec/new_integration/rack_app/rack_app_spec.rb +524 -0
  141. data/spec/new_integration/settings_spec.rb +115 -0
  142. data/spec/new_integration/slices/external_slice_spec.rb +92 -0
  143. data/spec/new_integration/slices/slice_configuration_spec.rb +40 -0
  144. data/spec/new_integration/slices/slice_routing_spec.rb +226 -0
  145. data/spec/new_integration/slices/slice_settings_spec.rb +141 -0
  146. data/spec/new_integration/slices_spec.rb +101 -0
  147. data/spec/new_integration/view/configuration_spec.rb +49 -0
  148. data/spec/new_integration/view/context/assets_spec.rb +67 -0
  149. data/spec/new_integration/view/context/inflector_spec.rb +48 -0
  150. data/spec/new_integration/view/context/request_spec.rb +61 -0
  151. data/spec/new_integration/view/context/routes_spec.rb +86 -0
  152. data/spec/new_integration/view/context/settings_spec.rb +50 -0
  153. data/spec/new_integration/view/inflector_spec.rb +57 -0
  154. data/spec/new_integration/view/part_namespace_spec.rb +96 -0
  155. data/spec/new_integration/view/path_spec.rb +56 -0
  156. data/spec/new_integration/view/template_spec.rb +68 -0
  157. data/spec/new_integration/view/views_spec.rb +103 -0
  158. data/spec/spec_helper.rb +16 -0
  159. data/spec/support/app_integration.rb +91 -0
  160. data/spec/support/coverage.rb +1 -0
  161. data/spec/support/fixtures/hanami-plugin/Gemfile +8 -0
  162. data/spec/support/fixtures/hanami-plugin/README.md +35 -0
  163. data/spec/support/fixtures/hanami-plugin/Rakefile +4 -0
  164. data/spec/support/fixtures/hanami-plugin/bin/console +15 -0
  165. data/spec/support/fixtures/hanami-plugin/bin/setup +8 -0
  166. data/spec/support/fixtures/hanami-plugin/hanami-plugin.gemspec +28 -0
  167. data/spec/support/fixtures/hanami-plugin/lib/hanami/plugin/cli.rb +19 -0
  168. data/spec/support/fixtures/hanami-plugin/lib/hanami/plugin/version.rb +7 -0
  169. data/spec/support/fixtures/hanami-plugin/lib/hanami/plugin.rb +8 -0
  170. data/spec/support/rspec.rb +27 -0
  171. data/spec/support/shared_examples/cli/generate/app.rb +494 -0
  172. data/spec/support/shared_examples/cli/generate/migration.rb +32 -0
  173. data/spec/support/shared_examples/cli/generate/model.rb +81 -0
  174. data/spec/support/shared_examples/cli/new.rb +97 -0
  175. data/spec/unit/hanami/configuration/actions/content_security_policy_spec.rb +102 -0
  176. data/spec/unit/hanami/configuration/actions/cookies_spec.rb +46 -0
  177. data/spec/unit/hanami/configuration/actions/csrf_protection_spec.rb +57 -0
  178. data/spec/unit/hanami/configuration/actions/default_values_spec.rb +52 -0
  179. data/spec/unit/hanami/configuration/actions/sessions_spec.rb +50 -0
  180. data/spec/unit/hanami/configuration/actions_spec.rb +78 -0
  181. data/spec/unit/hanami/configuration/base_url_spec.rb +25 -0
  182. data/spec/unit/hanami/configuration/inflector_spec.rb +35 -0
  183. data/spec/unit/hanami/configuration/logger_spec.rb +203 -0
  184. data/spec/unit/hanami/configuration/views_spec.rb +120 -0
  185. data/spec/unit/hanami/configuration_spec.rb +43 -0
  186. data/spec/unit/hanami/env_spec.rb +54 -0
  187. data/spec/unit/hanami/routes_spec.rb +25 -0
  188. data/spec/unit/hanami/settings/dotenv_store_spec.rb +119 -0
  189. data/spec/unit/hanami/settings_spec.rb +56 -0
  190. data/spec/unit/hanami/slice_configurable_spec.rb +104 -0
  191. data/spec/unit/hanami/slice_name_spec.rb +47 -0
  192. data/spec/unit/hanami/slice_spec.rb +17 -0
  193. data/spec/unit/hanami/version_spec.rb +7 -0
  194. data/spec/unit/hanami/web/rack_logger_spec.rb +78 -0
  195. metadata +353 -57
  196. data/lib/hanami/application/action.rb +0 -72
  197. data/lib/hanami/application/container/providers/inflector.rb +0 -7
  198. data/lib/hanami/application/container/providers/logger.rb +0 -7
  199. data/lib/hanami/application/container/providers/rack_logger.rb +0 -15
  200. data/lib/hanami/application/container/providers/rack_monitor.rb +0 -12
  201. data/lib/hanami/application/container/providers/routes_helper.rb +0 -9
  202. data/lib/hanami/application/container/providers/settings.rb +0 -7
  203. data/lib/hanami/application/routes.rb +0 -55
  204. data/lib/hanami/application/routes_helper.rb +0 -34
  205. data/lib/hanami/application/routing/resolver/node.rb +0 -50
  206. data/lib/hanami/application/routing/resolver/trie.rb +0 -59
  207. data/lib/hanami/application/routing/resolver.rb +0 -87
  208. data/lib/hanami/application/routing/router.rb +0 -36
  209. data/lib/hanami/application/settings/dotenv_store.rb +0 -60
  210. data/lib/hanami/application/settings.rb +0 -93
  211. data/lib/hanami/application/slice_registrar.rb +0 -106
  212. data/lib/hanami/application/view/context.rb +0 -95
  213. data/lib/hanami/application/view.rb +0 -24
  214. data/lib/hanami/application.rb +0 -273
  215. data/lib/hanami/cli/application/cli.rb +0 -40
  216. data/lib/hanami/cli/application/command.rb +0 -47
  217. data/lib/hanami/cli/application/commands/console.rb +0 -81
  218. data/lib/hanami/cli/application/commands.rb +0 -16
  219. data/lib/hanami/cli/base_command.rb +0 -48
  220. data/lib/hanami/cli/commands/command.rb +0 -171
  221. data/lib/hanami/cli/commands/server.rb +0 -88
  222. data/lib/hanami/cli/commands.rb +0 -65
  223. data/lib/hanami/configuration/middleware.rb +0 -20
  224. data/lib/hanami/configuration/source_dirs.rb +0 -42
@@ -0,0 +1,524 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rack/test"
4
+
5
+ RSpec.describe "Hanami web app", :app_integration do
6
+ include Rack::Test::Methods
7
+
8
+ let(:app) { Hanami.app }
9
+
10
+ specify "Hanami.app returns a rack builder" do
11
+ with_tmp_directory do
12
+ write "config/app.rb", <<~RUBY
13
+ require "hanami"
14
+
15
+ module TestApp
16
+ class App < Hanami::App
17
+ end
18
+ end
19
+ RUBY
20
+
21
+ write "config/routes.rb", <<~RUBY
22
+ module TestApp
23
+ class Routes < Hanami::Routes
24
+ define do
25
+ root to: ->(env) { [200, {}, ["OK"]] }
26
+ end
27
+ end
28
+ end
29
+ RUBY
30
+
31
+ require "hanami/boot"
32
+
33
+ expect(app).to be(TestApp::App)
34
+ end
35
+ end
36
+
37
+ specify "Has rack monitor preconfigured with default request logging" do
38
+ dir = Dir.mktmpdir
39
+
40
+ with_tmp_directory(dir) do
41
+ write "config/app.rb", <<~RUBY
42
+ require "hanami"
43
+
44
+ module TestApp
45
+ class App < Hanami::App
46
+ config.logger.stream = config.root.join("test.log")
47
+ end
48
+ end
49
+ RUBY
50
+
51
+ write "config/routes.rb", <<~RUBY
52
+ module TestApp
53
+ class Routes < Hanami::Routes
54
+ define do
55
+ end
56
+ end
57
+ end
58
+ RUBY
59
+
60
+ require "hanami/boot"
61
+
62
+ expect(Hanami.app["rack.monitor"]).to be_instance_of(Dry::Monitor::Rack::Middleware)
63
+
64
+ get "/"
65
+
66
+ logs = -> { Pathname(dir).join("test.log").realpath.read }
67
+
68
+ expect(logs.()).to match %r{GET 404 \d+ms 127.0.0.1 /}
69
+ end
70
+ end
71
+
72
+ describe "Request logging when using a slice" do
73
+ let(:app) { Main::Slice.rack_app }
74
+
75
+ specify "Has rack monitor preconfigured with default request logging (when used via a slice)" do
76
+ dir = Dir.mktmpdir
77
+
78
+ with_tmp_directory(dir) do
79
+ write "config/app.rb", <<~RUBY
80
+ require "hanami"
81
+
82
+ module TestApp
83
+ class App < Hanami::App
84
+ config.logger.stream = config.root.join("test.log")
85
+ end
86
+ end
87
+ RUBY
88
+
89
+ write "slices/main/config/routes.rb", <<~RUBY
90
+ module Main
91
+ class Routes < Hanami::Routes
92
+ define do
93
+ end
94
+ end
95
+ end
96
+ RUBY
97
+
98
+ require "hanami/boot"
99
+
100
+ get "/"
101
+
102
+ logs = -> { Pathname(dir).join("test.log").realpath.read }
103
+
104
+ expect(logs.()).to match %r{GET 404 \d+ms 127.0.0.1 /}
105
+ end
106
+ end
107
+ end
108
+
109
+ specify "Routing to actions based on their container identifiers" do
110
+ with_tmp_directory(Dir.mktmpdir) do
111
+ write "config/app.rb", <<~RUBY
112
+ require "hanami"
113
+
114
+ module TestApp
115
+ class App < Hanami::App
116
+ config.logger.stream = File.new("/dev/null", "w")
117
+ end
118
+ end
119
+ RUBY
120
+
121
+ write "config/routes.rb", <<~RUBY
122
+ module TestApp
123
+ class Routes < Hanami::Routes
124
+ define do
125
+ get "/health", to: "health.show"
126
+
127
+ get "/inline" do
128
+ "Inline"
129
+ end
130
+
131
+ slice :main, at: "/" do
132
+ root to: "home.index"
133
+ end
134
+
135
+ slice :admin, at: "/admin" do
136
+ get "/dashboard", to: "dashboard.show"
137
+ end
138
+ end
139
+ end
140
+ end
141
+ RUBY
142
+
143
+ write "app/actions/health/show.rb", <<~RUBY
144
+ require "hanami/action"
145
+
146
+ module TestApp
147
+ module Actions
148
+ module Health
149
+ class Show < Hanami::Action
150
+ def handle(*, res)
151
+ res.body = "Health, OK"
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
157
+ RUBY
158
+
159
+ write "slices/main/actions/home/index.rb", <<~RUBY
160
+ require "hanami/action"
161
+
162
+ module Main
163
+ module Actions
164
+ module Home
165
+ class Index < Hanami::Action
166
+ def handle(*, res)
167
+ res.body = "Hello world"
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
173
+ RUBY
174
+
175
+ write "slices/admin/actions/dashboard/show.rb", <<~RUBY
176
+ require "hanami/action"
177
+
178
+ module Admin
179
+ module Actions
180
+ module Dashboard
181
+ class Show < Hanami::Action
182
+ def handle(*, res)
183
+ res.body = "Admin dashboard here"
184
+ end
185
+ end
186
+ end
187
+ end
188
+ end
189
+ RUBY
190
+
191
+ require "hanami/boot"
192
+
193
+ get "/"
194
+
195
+ expect(last_response.status).to eq 200
196
+ expect(last_response.body).to eq "Hello world"
197
+
198
+ get "/inline"
199
+
200
+ expect(last_response.status).to eq 200
201
+ expect(last_response.body).to eq "Inline"
202
+
203
+ get "/health"
204
+
205
+ expect(last_response.status).to eq 200
206
+ expect(last_response.body).to eq "Health, OK"
207
+
208
+ get "/admin/dashboard"
209
+
210
+ expect(last_response.status).to eq 200
211
+ expect(last_response.body).to eq "Admin dashboard here"
212
+ end
213
+ end
214
+
215
+ # TODO: is this test even needed, given this is standard hanami-router behavior?
216
+ specify "It gives priority to the last declared route" do
217
+ with_tmp_directory(Dir.mktmpdir) do
218
+ write "config/app.rb", <<~RUBY
219
+ require "hanami"
220
+
221
+ module TestApp
222
+ class App < Hanami::App
223
+ config.logger.stream = File.new("/dev/null", "w")
224
+ end
225
+ end
226
+ RUBY
227
+
228
+ write "config/routes.rb", <<~RUBY
229
+ module TestApp
230
+ class Routes < Hanami::Routes
231
+ define do
232
+ root to: "home.index"
233
+
234
+ slice :main, at: "/" do
235
+ root to: "home.index"
236
+ end
237
+ end
238
+ end
239
+ end
240
+ RUBY
241
+
242
+ write "app/actions/home/index.rb", <<~RUBY
243
+ require "hanami/action"
244
+
245
+ module TestApp
246
+ module Actions
247
+ module Home
248
+ class Index < Hanami::Action
249
+ def handle(*, res)
250
+ res.body = "Hello from App"
251
+ end
252
+ end
253
+ end
254
+ end
255
+ end
256
+ RUBY
257
+
258
+ write "slices/main/actions/home/index.rb", <<~RUBY
259
+ require "hanami/action"
260
+
261
+ module Main
262
+ module Actions
263
+ module Home
264
+ class Index < Hanami::Action
265
+ def handle(*, res)
266
+ res.body = "Hello from Slice"
267
+ end
268
+ end
269
+ end
270
+ end
271
+ end
272
+ RUBY
273
+
274
+ require "hanami/boot"
275
+
276
+ get "/"
277
+
278
+ expect(last_response.status).to eq 200
279
+ expect(last_response.body).to eq "Hello from Slice"
280
+ end
281
+ end
282
+
283
+ specify "It does not choose actions from slice to route in app" do
284
+ with_tmp_directory(Dir.mktmpdir) do
285
+ write "config/app.rb", <<~RUBY
286
+ require "hanami"
287
+
288
+ module TestApp
289
+ class App < Hanami::App
290
+ config.logger.stream = File.new("/dev/null", "w")
291
+ end
292
+ end
293
+ RUBY
294
+
295
+ write "config/routes.rb", <<~RUBY
296
+ module TestApp
297
+ class Routes < Hanami::Routes
298
+ define do
299
+ get "/feedbacks", to: "feedbacks.index"
300
+
301
+ slice :api, at: "/api" do
302
+ get "/people", to: "people.index"
303
+ end
304
+ end
305
+ end
306
+ end
307
+ RUBY
308
+
309
+ write "app/action.rb", <<~RUBY
310
+ # auto_register: false
311
+ require "hanami/action"
312
+
313
+ module TestApp
314
+ class Action < Hanami::Action
315
+ end
316
+ end
317
+ RUBY
318
+
319
+ write "app/actions/feedbacks/index.rb", <<~RUBY
320
+ module TestApp
321
+ module Actions
322
+ module Feedbacks
323
+ class Index < TestApp::Action
324
+ def handle(*, res)
325
+ res.body = "Feedbacks"
326
+ end
327
+ end
328
+ end
329
+ end
330
+ end
331
+ RUBY
332
+
333
+ write "slices/api/action.rb", <<~RUBY
334
+ module API
335
+ class Action < TestApp::Action
336
+ end
337
+ end
338
+ RUBY
339
+
340
+ write "slices/api/actions/people/index.rb", <<~RUBY
341
+ module API
342
+ module Actions
343
+ module People
344
+ class Index < API::Action
345
+ def handle(*, res)
346
+ res.body = "People"
347
+ end
348
+ end
349
+ end
350
+ end
351
+ end
352
+ RUBY
353
+
354
+ require "hanami/boot"
355
+
356
+ get "/api/people"
357
+
358
+ expect(last_response.status).to eq 200
359
+ expect(last_response.body).to eq "People"
360
+ end
361
+ end
362
+
363
+ specify "For a booted app, rack_app raises an exception if a referenced action isn't registered in the app" do
364
+ with_tmp_directory(Dir.mktmpdir) do
365
+ write "config/app.rb", <<~RUBY
366
+ require "hanami"
367
+
368
+ module TestApp
369
+ class App < Hanami::App
370
+ end
371
+ end
372
+ RUBY
373
+
374
+ write "config/routes.rb", <<~RUBY
375
+ module TestApp
376
+ class Routes < Hanami::Routes
377
+ define do
378
+ get "/missing", to: "missing.action"
379
+ end
380
+ end
381
+ end
382
+ RUBY
383
+
384
+ require "hanami/boot"
385
+
386
+ expect { Hanami.app.rack_app }.to raise_error do |exception|
387
+ expect(exception).to be_kind_of(Hanami::Slice::Routing::UnknownActionError)
388
+ expect(exception.message).to include("missing.action")
389
+ end
390
+ end
391
+ end
392
+
393
+ specify "For a booted app, rack_app raises an error if a referenced action isn't registered in a slice" do
394
+ with_tmp_directory(Dir.mktmpdir) do
395
+ write "config/app.rb", <<~RUBY
396
+ require "hanami"
397
+
398
+ module TestApp
399
+ class App < Hanami::App
400
+ register_slice :admin
401
+ end
402
+ end
403
+ RUBY
404
+
405
+ write "config/routes.rb", <<~RUBY
406
+ module TestApp
407
+ class Routes < Hanami::Routes
408
+ define do
409
+ slice :admin, at: "/admin" do
410
+ get "/missing", to: "missing.action"
411
+ end
412
+ end
413
+ end
414
+ end
415
+ RUBY
416
+
417
+ require "hanami/boot"
418
+
419
+ expect { Hanami.app.rack_app }.to raise_error do |exception|
420
+ expect(exception).to be_kind_of(Hanami::Slice::Routing::UnknownActionError)
421
+ expect(exception.message).to include("missing.action")
422
+ end
423
+ end
424
+ end
425
+
426
+ specify "For a non-booted app, rack_app does not raise an error if a referenced action isn't registered in the app" do
427
+ with_tmp_directory(Dir.mktmpdir) do
428
+ write "config/app.rb", <<~RUBY
429
+ require "hanami"
430
+
431
+ module TestApp
432
+ class App < Hanami::App
433
+ end
434
+ end
435
+ RUBY
436
+
437
+ write "config/routes.rb", <<~RUBY
438
+ module TestApp
439
+ class Routes < Hanami::Routes
440
+ define do
441
+ get "/missing", to: "missing.action"
442
+ end
443
+ end
444
+ end
445
+ RUBY
446
+
447
+ require "hanami/prepare"
448
+
449
+ expect { Hanami.app.rack_app }.not_to raise_error
450
+
451
+ expect { get "/missing" }.to raise_error do |exception|
452
+ expect(exception).to be_kind_of(Hanami::Slice::Routing::UnknownActionError)
453
+ expect(exception.message).to include("missing.action")
454
+ end
455
+ end
456
+ end
457
+
458
+ specify "For a non-booted app, rack_app does not raise an error if a referenced action isn't registered in a slice" do
459
+ with_tmp_directory(Dir.mktmpdir) do
460
+ write "config/app.rb", <<~RUBY
461
+ require "hanami"
462
+
463
+ module TestApp
464
+ class App < Hanami::App
465
+ register_slice :admin
466
+ end
467
+ end
468
+ RUBY
469
+
470
+ write "config/routes.rb", <<~RUBY
471
+ module TestApp
472
+ class Routes < Hanami::Routes
473
+ define do
474
+ slice :admin, at: "/admin" do
475
+ get "/missing", to: "missing.action"
476
+ end
477
+ end
478
+ end
479
+ end
480
+ RUBY
481
+
482
+ require "hanami/prepare"
483
+
484
+ expect { Hanami.app.rack_app }.not_to raise_error
485
+
486
+ expect { get "/admin/missing" }.to raise_error do |exception|
487
+ expect(exception).to be_kind_of(Hanami::Slice::Routing::UnknownActionError)
488
+ expect(exception.message).to include("missing.action")
489
+ end
490
+ end
491
+ end
492
+
493
+ specify "rack_app raises an error if a referenced slice is not registered" do
494
+ with_tmp_directory(Dir.mktmpdir) do
495
+ write "config/app.rb", <<~RUBY
496
+ require "hanami"
497
+
498
+ module TestApp
499
+ class App < Hanami::App
500
+ end
501
+ end
502
+ RUBY
503
+
504
+ write "config/routes.rb", <<~RUBY
505
+ module TestApp
506
+ class Routes < Hanami::Routes
507
+ define do
508
+ slice :foo, at: "/foo" do
509
+ get "/bar", to: "bar.index"
510
+ end
511
+ end
512
+ end
513
+ end
514
+ RUBY
515
+
516
+ require "hanami/prepare"
517
+
518
+ expect { Hanami.app.rack_app }.to raise_error do |exception|
519
+ expect(exception).to be_kind_of(Hanami::SliceLoadError)
520
+ expect(exception.message).to include("Slice 'foo' not found")
521
+ end
522
+ end
523
+ end
524
+ end
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "hanami/settings"
4
+
5
+ RSpec.describe "App settings", :app_integration do
6
+ before do
7
+ @env = ENV.to_h
8
+ end
9
+
10
+ after do
11
+ ENV.replace(@env)
12
+ end
13
+
14
+ specify "Settings defined in config/settings.rb are loaded from .env" do
15
+ with_tmp_directory(Dir.mktmpdir) do
16
+ write "config/app.rb", <<~RUBY
17
+ require "hanami"
18
+
19
+ module TestApp
20
+ class App < Hanami::App
21
+ end
22
+ end
23
+ RUBY
24
+
25
+ write "config/settings.rb", <<~RUBY
26
+ require "hanami/settings"
27
+ require "test_app/types"
28
+
29
+ module TestApp
30
+ class Settings < Hanami::Settings
31
+ setting :database_url
32
+ setting :redis_url
33
+ setting :feature_flag, constructor: TestApp::Types::Params::Bool
34
+ setting :feature_flag_with_default, default: false, constructor: TestApp::Types::Params::Bool
35
+ end
36
+ end
37
+ RUBY
38
+
39
+ write ".env", <<~RUBY
40
+ DATABASE_URL=postgres://localhost/test_app_development
41
+ REDIS_URL=redis://localhost:6379
42
+ FEATURE_FLAG=true
43
+ RUBY
44
+
45
+ write "lib/test_app/types.rb", <<~RUBY
46
+ require "dry/types"
47
+
48
+ module TestApp
49
+ module Types
50
+ include Dry.Types()
51
+ end
52
+ end
53
+ RUBY
54
+
55
+ require "hanami/prepare"
56
+
57
+ expect(Hanami.app.settings.database_url).to eq "postgres://localhost/test_app_development"
58
+ expect(Hanami.app.settings.redis_url).to eq "redis://localhost:6379"
59
+ expect(Hanami.app.settings.feature_flag).to be true
60
+ expect(Hanami.app.settings.feature_flag_with_default).to be false
61
+
62
+ expect(Hanami.app[:settings]).to eql Hanami.app.settings
63
+ end
64
+ end
65
+
66
+ specify "Errors raised from setting constructors are collected" do
67
+ with_tmp_directory(Dir.mktmpdir) do
68
+ write "config/app.rb", <<~RUBY
69
+ require "hanami"
70
+
71
+ module TestApp
72
+ class App < Hanami::App
73
+ end
74
+ end
75
+ RUBY
76
+
77
+ write "config/settings.rb", <<~RUBY
78
+ require "hanami/settings"
79
+ require "test_app/types"
80
+
81
+ module TestApp
82
+ class Settings < Hanami::Settings
83
+ setting :numeric_setting, constructor: TestApp::Types::Params::Integer
84
+ setting :feature_flag, constructor: TestApp::Types::Params::Bool
85
+ end
86
+ end
87
+ RUBY
88
+
89
+ write ".env", <<~RUBY
90
+ NUMERIC_SETTING=hello
91
+ FEATURE_FLAG=maybe
92
+ RUBY
93
+
94
+ write "lib/test_app/types.rb", <<~RUBY
95
+ require "dry/types"
96
+
97
+ module TestApp
98
+ module Types
99
+ include Dry.Types()
100
+ end
101
+ end
102
+ RUBY
103
+
104
+ numeric_setting_error = "numeric_setting: invalid value for Integer"
105
+ feature_flag_error = "feature_flag: maybe cannot be coerced"
106
+
107
+ expect {
108
+ require "hanami/prepare"
109
+ }.to raise_error(
110
+ Hanami::Settings::InvalidSettingsError,
111
+ /#{numeric_setting_error}.+#{feature_flag_error}|#{feature_flag_error}.+#{numeric_setting_error}/m
112
+ )
113
+ end
114
+ end
115
+ end