hanami 2.3.2 → 3.0.0.rc1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +55 -19
- data/LICENSE +20 -0
- data/README.md +18 -35
- data/hanami.gemspec +36 -37
- data/lib/hanami/config/db.rb +2 -0
- data/lib/hanami/config/i18n.rb +138 -0
- data/lib/hanami/config/logger.rb +15 -7
- data/lib/hanami/config/null_config.rb +1 -1
- data/lib/hanami/config/views.rb +17 -0
- data/lib/hanami/config.rb +66 -22
- data/lib/hanami/errors.rb +6 -0
- data/lib/hanami/extensions/action/slice_configured_action.rb +1 -1
- data/lib/hanami/extensions/action.rb +2 -2
- data/lib/hanami/extensions/mailer/slice_configured_mailer.rb +120 -0
- data/lib/hanami/extensions/mailer.rb +28 -0
- data/lib/hanami/extensions/operation/slice_configured_db_operation.rb +2 -0
- data/lib/hanami/extensions/view/context.rb +26 -4
- data/lib/hanami/extensions/view/part.rb +2 -0
- data/lib/hanami/extensions/view/slice_configured_context.rb +7 -0
- data/lib/hanami/extensions/view/slice_configured_part.rb +2 -0
- data/lib/hanami/extensions/view/slice_configured_view.rb +8 -8
- data/lib/hanami/extensions/view/standard_helpers.rb +4 -0
- data/lib/hanami/extensions.rb +6 -1
- data/lib/hanami/helpers/assets_helper.rb +0 -4
- data/lib/hanami/helpers/form_helper.rb +1 -1
- data/lib/hanami/helpers/i18n_helper.rb +176 -0
- data/lib/hanami/logger/rack_formatter.rb +73 -0
- data/lib/hanami/logger/sql_formatter.rb +80 -0
- data/lib/hanami/logger/sql_logger.rb +48 -0
- data/lib/hanami/middleware/render_errors.rb +2 -2
- data/lib/hanami/providers/db.rb +7 -2
- data/lib/hanami/providers/db_logging.rb +4 -7
- data/lib/hanami/providers/i18n/backend.rb +369 -0
- data/lib/hanami/providers/i18n/locale/en.yml +57 -0
- data/lib/hanami/providers/i18n.rb +114 -0
- data/lib/hanami/providers/mailers.rb +101 -0
- data/lib/hanami/routes.rb +1 -0
- data/lib/hanami/settings/composite_store.rb +53 -0
- data/lib/hanami/settings.rb +4 -4
- data/lib/hanami/slice/router.rb +15 -10
- data/lib/hanami/slice.rb +71 -11
- data/lib/hanami/slice_registrar.rb +2 -2
- data/lib/hanami/universal_logger.rb +250 -0
- data/lib/hanami/version.rb +1 -1
- data/lib/hanami/web/rack_logger.rb +2 -80
- data/lib/hanami/web/welcome.html.erb +443 -58
- data/lib/hanami.rb +4 -2
- metadata +28 -276
- data/CODE_OF_CONDUCT.md +0 -74
- data/FEATURES.md +0 -269
- data/LICENSE.md +0 -22
- data/spec/integration/action/cookies_spec.rb +0 -58
- data/spec/integration/action/csrf_protection_spec.rb +0 -54
- data/spec/integration/action/format_config_spec.rb +0 -129
- data/spec/integration/action/routes_spec.rb +0 -71
- data/spec/integration/action/sessions_spec.rb +0 -50
- data/spec/integration/action/slice_configuration_spec.rb +0 -284
- data/spec/integration/action/view_rendering/automatic_rendering_spec.rb +0 -247
- data/spec/integration/action/view_rendering/paired_view_inference_spec.rb +0 -115
- data/spec/integration/action/view_rendering/view_context_spec.rb +0 -221
- data/spec/integration/action/view_rendering_spec.rb +0 -89
- data/spec/integration/assets/assets_spec.rb +0 -155
- data/spec/integration/assets/cross_slice_assets_helpers_spec.rb +0 -129
- data/spec/integration/assets/serve_static_assets_spec.rb +0 -152
- data/spec/integration/code_loading/loading_from_app_spec.rb +0 -152
- data/spec/integration/code_loading/loading_from_lib_spec.rb +0 -242
- data/spec/integration/code_loading/loading_from_slice_spec.rb +0 -165
- data/spec/integration/container/application_routes_helper_spec.rb +0 -48
- data/spec/integration/container/auto_injection_spec.rb +0 -53
- data/spec/integration/container/auto_registration_spec.rb +0 -86
- data/spec/integration/container/autoloader_spec.rb +0 -82
- data/spec/integration/container/imports_spec.rb +0 -253
- data/spec/integration/container/prepare_container_spec.rb +0 -125
- data/spec/integration/container/provider_environment_spec.rb +0 -52
- data/spec/integration/container/provider_lifecycle_spec.rb +0 -61
- data/spec/integration/container/shutdown_spec.rb +0 -91
- data/spec/integration/container/standard_providers/rack_provider_spec.rb +0 -44
- data/spec/integration/container/standard_providers_spec.rb +0 -124
- data/spec/integration/db/auto_registration_spec.rb +0 -39
- data/spec/integration/db/commands_spec.rb +0 -80
- data/spec/integration/db/db_inflector_spec.rb +0 -57
- data/spec/integration/db/db_slices_spec.rb +0 -398
- data/spec/integration/db/db_spec.rb +0 -245
- data/spec/integration/db/gateways_spec.rb +0 -361
- data/spec/integration/db/logging_spec.rb +0 -301
- data/spec/integration/db/mappers_spec.rb +0 -84
- data/spec/integration/db/provider_config_spec.rb +0 -88
- data/spec/integration/db/provider_spec.rb +0 -35
- data/spec/integration/db/relations_spec.rb +0 -60
- data/spec/integration/db/repo_spec.rb +0 -300
- data/spec/integration/db/slices_importing_from_parent.rb +0 -130
- data/spec/integration/dotenv_loading_spec.rb +0 -138
- data/spec/integration/logging/exception_logging_spec.rb +0 -120
- data/spec/integration/logging/notifications_spec.rb +0 -68
- data/spec/integration/logging/request_logging_spec.rb +0 -202
- data/spec/integration/operations/extension_spec.rb +0 -122
- data/spec/integration/rack_app/body_parser_spec.rb +0 -108
- data/spec/integration/rack_app/method_override_spec.rb +0 -97
- data/spec/integration/rack_app/middleware_spec.rb +0 -720
- data/spec/integration/rack_app/non_booted_rack_app_spec.rb +0 -104
- data/spec/integration/rack_app/rack_app_spec.rb +0 -442
- data/spec/integration/rake_tasks_spec.rb +0 -107
- data/spec/integration/router/resource_routes_spec.rb +0 -281
- data/spec/integration/settings/access_in_slice_class_body_spec.rb +0 -83
- data/spec/integration/settings/access_to_constants_spec.rb +0 -46
- data/spec/integration/settings/loading_from_env_spec.rb +0 -188
- data/spec/integration/settings/settings_component_loading_spec.rb +0 -113
- data/spec/integration/settings/slice_registration_spec.rb +0 -145
- data/spec/integration/settings/using_types_spec.rb +0 -80
- data/spec/integration/setup_spec.rb +0 -165
- data/spec/integration/slices/external_slice_spec.rb +0 -91
- data/spec/integration/slices/slice_configuration_spec.rb +0 -42
- data/spec/integration/slices/slice_loading_spec.rb +0 -171
- data/spec/integration/slices/slice_registrations_spec.rb +0 -80
- data/spec/integration/slices/slice_routing_spec.rb +0 -219
- data/spec/integration/slices_spec.rb +0 -471
- data/spec/integration/view/config/default_context_spec.rb +0 -149
- data/spec/integration/view/config/inflector_spec.rb +0 -57
- data/spec/integration/view/config/part_class_spec.rb +0 -147
- data/spec/integration/view/config/part_namespace_spec.rb +0 -103
- data/spec/integration/view/config/paths_spec.rb +0 -119
- data/spec/integration/view/config/scope_class_spec.rb +0 -147
- data/spec/integration/view/config/scope_namespace_spec.rb +0 -103
- data/spec/integration/view/config/template_spec.rb +0 -38
- data/spec/integration/view/context/assets_spec.rb +0 -79
- data/spec/integration/view/context/inflector_spec.rb +0 -40
- data/spec/integration/view/context/request_spec.rb +0 -57
- data/spec/integration/view/context/routes_spec.rb +0 -84
- data/spec/integration/view/helpers/form_helper_spec.rb +0 -174
- data/spec/integration/view/helpers/part_helpers_spec.rb +0 -124
- data/spec/integration/view/helpers/scope_helpers_spec.rb +0 -84
- data/spec/integration/view/helpers/user_defined_helpers/part_helpers_spec.rb +0 -162
- data/spec/integration/view/helpers/user_defined_helpers/scope_helpers_spec.rb +0 -119
- data/spec/integration/view/parts/default_rendering_spec.rb +0 -138
- data/spec/integration/view/slice_configuration_spec.rb +0 -289
- data/spec/integration/view/views_spec.rb +0 -103
- data/spec/integration/web/content_security_policy_nonce_spec.rb +0 -251
- data/spec/integration/web/render_detailed_errors_spec.rb +0 -107
- data/spec/integration/web/render_errors_spec.rb +0 -242
- data/spec/integration/web/welcome_view_spec.rb +0 -84
- data/spec/spec_helper.rb +0 -28
- data/spec/support/app_integration.rb +0 -157
- data/spec/support/coverage.rb +0 -1
- data/spec/support/matchers.rb +0 -32
- data/spec/support/rspec.rb +0 -27
- data/spec/unit/hanami/config/actions/content_security_policy_spec.rb +0 -96
- data/spec/unit/hanami/config/actions/cookies_spec.rb +0 -46
- data/spec/unit/hanami/config/actions/csrf_protection_spec.rb +0 -58
- data/spec/unit/hanami/config/actions/default_values_spec.rb +0 -43
- data/spec/unit/hanami/config/actions/sessions_spec.rb +0 -48
- data/spec/unit/hanami/config/actions_spec.rb +0 -52
- data/spec/unit/hanami/config/base_url_spec.rb +0 -25
- data/spec/unit/hanami/config/console_spec.rb +0 -22
- data/spec/unit/hanami/config/db_spec.rb +0 -38
- data/spec/unit/hanami/config/inflector_spec.rb +0 -35
- data/spec/unit/hanami/config/logger_spec.rb +0 -195
- data/spec/unit/hanami/config/render_detailed_errors_spec.rb +0 -25
- data/spec/unit/hanami/config/render_errors_spec.rb +0 -25
- data/spec/unit/hanami/config/router_spec.rb +0 -44
- data/spec/unit/hanami/config/slices_spec.rb +0 -34
- data/spec/unit/hanami/config/views_spec.rb +0 -80
- data/spec/unit/hanami/env_spec.rb +0 -37
- data/spec/unit/hanami/extensions/view/context_spec.rb +0 -59
- data/spec/unit/hanami/helpers/assets_helper/asset_url_spec.rb +0 -120
- data/spec/unit/hanami/helpers/assets_helper/audio_tag_spec.rb +0 -132
- data/spec/unit/hanami/helpers/assets_helper/favicon_tag_spec.rb +0 -87
- data/spec/unit/hanami/helpers/assets_helper/image_tag_spec.rb +0 -92
- data/spec/unit/hanami/helpers/assets_helper/javascript_tag_spec.rb +0 -143
- data/spec/unit/hanami/helpers/assets_helper/stylesheet_tag_spec.rb +0 -126
- data/spec/unit/hanami/helpers/assets_helper/video_tag_spec.rb +0 -136
- data/spec/unit/hanami/helpers/form_helper_spec.rb +0 -2857
- data/spec/unit/hanami/port_spec.rb +0 -117
- data/spec/unit/hanami/providers/db/config/default_config_spec.rb +0 -100
- data/spec/unit/hanami/providers/db/config/gateway_spec.rb +0 -73
- data/spec/unit/hanami/providers/db/config_spec.rb +0 -143
- data/spec/unit/hanami/router/errors/not_allowed_error_spec.rb +0 -27
- data/spec/unit/hanami/router/errors/not_found_error_spec.rb +0 -22
- data/spec/unit/hanami/settings/env_store_spec.rb +0 -52
- data/spec/unit/hanami/settings_spec.rb +0 -111
- data/spec/unit/hanami/slice_configurable_spec.rb +0 -141
- data/spec/unit/hanami/slice_name_spec.rb +0 -47
- data/spec/unit/hanami/slice_spec.rb +0 -99
- data/spec/unit/hanami/web/rack_logger_spec.rb +0 -99
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "json"
|
|
4
|
-
require "rack/test"
|
|
5
|
-
|
|
6
|
-
RSpec.describe "Web / Rendering 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_errors = true
|
|
20
|
-
config.render_detailed_errors = false
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
RUBY
|
|
24
|
-
|
|
25
|
-
write "config/routes.rb", <<~RUBY
|
|
26
|
-
module TestApp
|
|
27
|
-
class Routes < Hanami::Routes
|
|
28
|
-
get "index", to: "index"
|
|
29
|
-
get "error", to: "error"
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
RUBY
|
|
33
|
-
|
|
34
|
-
write "app/actions/index.rb", <<~RUBY
|
|
35
|
-
module TestApp
|
|
36
|
-
module Actions
|
|
37
|
-
class Index < Hanami::Action
|
|
38
|
-
def handle(*, response)
|
|
39
|
-
response.body = "Hello"
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
RUBY
|
|
45
|
-
|
|
46
|
-
write "app/actions/error.rb", <<~RUBY
|
|
47
|
-
module TestApp
|
|
48
|
-
module Actions
|
|
49
|
-
class Error < Hanami::Action
|
|
50
|
-
def handle(*)
|
|
51
|
-
raise "oops"
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
RUBY
|
|
57
|
-
|
|
58
|
-
before_prepare if respond_to?(:before_prepare)
|
|
59
|
-
require "hanami/prepare"
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
describe "HTML request" do
|
|
64
|
-
context "error pages present" do
|
|
65
|
-
def before_prepare
|
|
66
|
-
write "public/404.html", <<~HTML
|
|
67
|
-
<h1>Not found</h1>
|
|
68
|
-
HTML
|
|
69
|
-
|
|
70
|
-
write "public/500.html", <<~HTML
|
|
71
|
-
<h1>Error</h1>
|
|
72
|
-
HTML
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
it "responds with the HTML for a 404 from a not found error" do
|
|
76
|
-
get "/__not_found__"
|
|
77
|
-
|
|
78
|
-
expect(last_response.status).to eq 404
|
|
79
|
-
expect(last_response.body.strip).to eq "<h1>Not found</h1>"
|
|
80
|
-
expect(last_response.get_header("Content-Type")).to eq "text/html; charset=utf-8"
|
|
81
|
-
expect(last_response.get_header("Content-Length")).to eq "19"
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
it "responds with the HTML for a 404 from a method not allowed error" do
|
|
85
|
-
post "/index"
|
|
86
|
-
|
|
87
|
-
expect(last_response.status).to eq 404
|
|
88
|
-
expect(last_response.body.strip).to eq "<h1>Not found</h1>"
|
|
89
|
-
expect(last_response.get_header("Content-Type")).to eq "text/html; charset=utf-8"
|
|
90
|
-
expect(last_response.get_header("Content-Length")).to eq "19"
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
it "responds with the HTML for a 500" do
|
|
94
|
-
get "/error"
|
|
95
|
-
|
|
96
|
-
expect(last_response.status).to eq 500
|
|
97
|
-
expect(last_response.body.strip).to eq "<h1>Error</h1>"
|
|
98
|
-
expect(last_response.get_header("Content-Type")).to eq "text/html; charset=utf-8"
|
|
99
|
-
expect(last_response.get_header("Content-Length")).to eq "15"
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
context "error pages missing" do
|
|
104
|
-
it "responds with default text for a 404 from a not found error" do
|
|
105
|
-
get "/__not_found__"
|
|
106
|
-
|
|
107
|
-
expect(last_response.status).to eq 404
|
|
108
|
-
expect(last_response.body.strip).to eq "Not Found"
|
|
109
|
-
expect(last_response.get_header("Content-Type")).to eq "text/html; charset=utf-8"
|
|
110
|
-
expect(last_response.get_header("Content-Length")).to eq "9"
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
it "responds with default text for a 404 from a metohd not allowed error" do
|
|
114
|
-
post "/index"
|
|
115
|
-
|
|
116
|
-
expect(last_response.status).to eq 404
|
|
117
|
-
expect(last_response.body.strip).to eq "Not Found"
|
|
118
|
-
expect(last_response.get_header("Content-Type")).to eq "text/html; charset=utf-8"
|
|
119
|
-
expect(last_response.get_header("Content-Length")).to eq "9"
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
it "responds with default text for a 500" do
|
|
123
|
-
get "/error"
|
|
124
|
-
|
|
125
|
-
expect(last_response.status).to eq 500
|
|
126
|
-
expect(last_response.body.strip).to eq "Internal Server Error"
|
|
127
|
-
expect(last_response.get_header("Content-Type")).to eq "text/html; charset=utf-8"
|
|
128
|
-
expect(last_response.get_header("Content-Length")).to eq "21"
|
|
129
|
-
end
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
describe "JSON request" do
|
|
134
|
-
it "renders a JSON response for a 404 from a not found error" do
|
|
135
|
-
get "/__not_found__", {}, "HTTP_ACCEPT" => "application/json"
|
|
136
|
-
|
|
137
|
-
expect(last_response.status).to eq 404
|
|
138
|
-
expect(last_response.body.strip).to eq %({"status":404,"error":"Not Found"})
|
|
139
|
-
expect(last_response.get_header("Content-Type")).to eq "application/json; charset=utf-8"
|
|
140
|
-
expect(last_response.get_header("Content-Length")).to eq "34"
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
it "renders a JSON response for a 404 from a metnod not allowed error" do
|
|
144
|
-
post "/index", {}, "HTTP_ACCEPT" => "application/json"
|
|
145
|
-
|
|
146
|
-
expect(last_response.status).to eq 404
|
|
147
|
-
expect(last_response.body.strip).to eq %({"status":404,"error":"Not Found"})
|
|
148
|
-
expect(last_response.get_header("Content-Type")).to eq "application/json; charset=utf-8"
|
|
149
|
-
expect(last_response.get_header("Content-Length")).to eq "34"
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
it "renders a JSON response for a 500" do
|
|
153
|
-
get "/error", {}, "HTTP_ACCEPT" => "application/json"
|
|
154
|
-
|
|
155
|
-
expect(last_response.status).to eq 500
|
|
156
|
-
expect(last_response.body.strip).to eq %({"status":500,"error":"Internal Server Error"})
|
|
157
|
-
expect(last_response.get_header("Content-Type")).to eq "application/json; charset=utf-8"
|
|
158
|
-
expect(last_response.get_header("Content-Length")).to eq "46"
|
|
159
|
-
end
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
describe "configuring error responses" do
|
|
163
|
-
def before_prepare
|
|
164
|
-
write "config/app.rb", <<~RUBY
|
|
165
|
-
require "hanami"
|
|
166
|
-
|
|
167
|
-
module TestApp
|
|
168
|
-
CustomNotFoundError = Class.new(StandardError)
|
|
169
|
-
|
|
170
|
-
class App < Hanami::App
|
|
171
|
-
config.logger.stream = File.new("/dev/null", "w")
|
|
172
|
-
config.render_errors = true
|
|
173
|
-
config.render_error_responses["TestApp::CustomNotFoundError"] = :not_found
|
|
174
|
-
config.render_detailed_errors = false
|
|
175
|
-
end
|
|
176
|
-
end
|
|
177
|
-
RUBY
|
|
178
|
-
|
|
179
|
-
write "app/actions/error.rb", <<~RUBY
|
|
180
|
-
module TestApp
|
|
181
|
-
module Actions
|
|
182
|
-
class Error < Hanami::Action
|
|
183
|
-
def handle(*)
|
|
184
|
-
raise CustomNotFoundError
|
|
185
|
-
end
|
|
186
|
-
end
|
|
187
|
-
end
|
|
188
|
-
end
|
|
189
|
-
RUBY
|
|
190
|
-
|
|
191
|
-
write "public/404.html", <<~HTML
|
|
192
|
-
<h1>Not found</h1>
|
|
193
|
-
HTML
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
it "uses the configured errors to determine the response" do
|
|
197
|
-
get "/error"
|
|
198
|
-
|
|
199
|
-
expect(last_response.status).to eq 404
|
|
200
|
-
expect(last_response.body.strip).to eq "<h1>Not found</h1>"
|
|
201
|
-
end
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
describe "render_errors config disabled" do
|
|
205
|
-
def before_prepare
|
|
206
|
-
write "config/app.rb", <<~RUBY
|
|
207
|
-
require "hanami"
|
|
208
|
-
|
|
209
|
-
module TestApp
|
|
210
|
-
class App < Hanami::App
|
|
211
|
-
config.logger.stream = File.new("/dev/null", "w")
|
|
212
|
-
config.render_errors = false
|
|
213
|
-
config.render_detailed_errors = false
|
|
214
|
-
end
|
|
215
|
-
end
|
|
216
|
-
RUBY
|
|
217
|
-
|
|
218
|
-
# Include error pages here to prove they are _not_ used
|
|
219
|
-
write "public/404.html", <<~HTML
|
|
220
|
-
<h1>Not found</h1>
|
|
221
|
-
HTML
|
|
222
|
-
|
|
223
|
-
write "public/500.html", <<~HTML
|
|
224
|
-
<h1>Error</h1>
|
|
225
|
-
HTML
|
|
226
|
-
end
|
|
227
|
-
|
|
228
|
-
it "renders the hanami-router default 404 response for a not found error" do
|
|
229
|
-
get "/__not_found__"
|
|
230
|
-
expect(last_response.status).to eq 404
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
it "renders the hanami-router default 405 response for a not allowed error" do
|
|
234
|
-
post "/index"
|
|
235
|
-
expect(last_response.status).to eq 405
|
|
236
|
-
end
|
|
237
|
-
|
|
238
|
-
it "raises the original error for a 500" do
|
|
239
|
-
expect { get "/error" }.to raise_error(RuntimeError, "oops")
|
|
240
|
-
end
|
|
241
|
-
end
|
|
242
|
-
end
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "json"
|
|
4
|
-
require "rack/test"
|
|
5
|
-
|
|
6
|
-
RSpec.describe "Web / Welcome view", :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::NULL
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
RUBY
|
|
22
|
-
|
|
23
|
-
write "config/routes.rb", <<~RUBY
|
|
24
|
-
module TestApp
|
|
25
|
-
class Routes < Hanami::Routes
|
|
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
|
-
context "no routes defined" do
|
|
36
|
-
it "renders the welcome page" do
|
|
37
|
-
get "/"
|
|
38
|
-
|
|
39
|
-
body = last_response.body.strip
|
|
40
|
-
expect(body).to include "<h1>Welcome to Hanami</h1>"
|
|
41
|
-
expect(body).to include "Hanami version: #{Hanami::VERSION}"
|
|
42
|
-
expect(body).to include "Ruby version: #{RUBY_DESCRIPTION}"
|
|
43
|
-
|
|
44
|
-
expect(last_response.status).to eq 200
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
context "routes defined" do
|
|
49
|
-
def before_prepare
|
|
50
|
-
write "config/routes.rb", <<~RUBY
|
|
51
|
-
module TestApp
|
|
52
|
-
class Routes < Hanami::Routes
|
|
53
|
-
root to: -> * { [200, {}, "Hello from a route"] }
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
RUBY
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
it "does not render the welcome page" do
|
|
60
|
-
get "/"
|
|
61
|
-
|
|
62
|
-
expect(last_response.body).to eq "Hello from a route"
|
|
63
|
-
expect(last_response.status).to eq 200
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
context "non-development env" do
|
|
68
|
-
def before_prepare
|
|
69
|
-
@hanami_env = ENV["HANAMI_ENV"]
|
|
70
|
-
ENV["HANAMI_ENV"] = "production"
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
after do
|
|
74
|
-
ENV["HANAMI_ENV"] = @hanami_env
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
it "does not render the welcome page" do
|
|
78
|
-
get "/"
|
|
79
|
-
|
|
80
|
-
expect(last_response.body).to eq "Not Found"
|
|
81
|
-
expect(last_response.status).to eq 404
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
end
|
data/spec/spec_helper.rb
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "pathname"
|
|
4
|
-
|
|
5
|
-
SPEC_ROOT = File.expand_path(__dir__).freeze
|
|
6
|
-
LOG_DIR = Pathname(SPEC_ROOT).join("..").join("log")
|
|
7
|
-
|
|
8
|
-
require_relative "support/coverage" if ENV["COVERAGE"].eql?("true")
|
|
9
|
-
|
|
10
|
-
require "hanami"
|
|
11
|
-
begin; require "byebug"; rescue LoadError; end
|
|
12
|
-
require "hanami/utils/file_list"
|
|
13
|
-
require "hanami/devtools/unit"
|
|
14
|
-
|
|
15
|
-
Hanami::Utils::FileList["./spec/support/**/*.rb"].each do |file|
|
|
16
|
-
next if file.include?("hanami-plugin")
|
|
17
|
-
|
|
18
|
-
require file
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
RSpec.configure do |config|
|
|
22
|
-
config.after(:suite) do
|
|
23
|
-
# TODO: Find out what causes logger to create this dir when running specs.
|
|
24
|
-
# There's probably a test app class being created somewhere with root
|
|
25
|
-
# not pointing to a tmp dir.
|
|
26
|
-
FileUtils.rm_rf(LOG_DIR) if LOG_DIR.exist?
|
|
27
|
-
end
|
|
28
|
-
end
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "hanami/devtools/integration/files"
|
|
4
|
-
require "hanami/devtools/integration/with_tmp_directory"
|
|
5
|
-
require "json"
|
|
6
|
-
require "tmpdir"
|
|
7
|
-
require "zeitwerk"
|
|
8
|
-
|
|
9
|
-
module RSpec
|
|
10
|
-
module Support
|
|
11
|
-
module WithTmpDirectory
|
|
12
|
-
private
|
|
13
|
-
|
|
14
|
-
def make_tmp_directory
|
|
15
|
-
Pathname(Dir.mktmpdir).tap do |dir|
|
|
16
|
-
(@made_tmp_dirs ||= []) << dir
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
module App
|
|
22
|
-
def self.included(base)
|
|
23
|
-
super
|
|
24
|
-
|
|
25
|
-
base.class_eval do
|
|
26
|
-
let!(:node_modules_path) { File.join(Dir.pwd, "node_modules") }
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
private
|
|
31
|
-
|
|
32
|
-
# TODO: make slice-aware
|
|
33
|
-
def stub_assets(*assets)
|
|
34
|
-
manifest_hash = assets.each_with_object({}) { |source_path, hsh|
|
|
35
|
-
hsh[source_path] = {url: File.join("/assets", source_path)}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
write "public/assets/assets.json", JSON.generate(manifest_hash)
|
|
39
|
-
|
|
40
|
-
# An assets dir is required to load the assets provider
|
|
41
|
-
write "app/assets/.keep", ""
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def compile_assets!
|
|
45
|
-
link_node_modules
|
|
46
|
-
generate_assets_config
|
|
47
|
-
|
|
48
|
-
require "hanami/cli/command"
|
|
49
|
-
require "hanami/cli/commands/app/command"
|
|
50
|
-
require "hanami/cli/commands/app/assets/compile"
|
|
51
|
-
assets_compile = Hanami::CLI::Commands::App::Assets::Compile.new(
|
|
52
|
-
config: Hanami.app.config.assets,
|
|
53
|
-
out: File.new(File::NULL, "w"),
|
|
54
|
-
err: File.new(File::NULL, "w"),
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
with_directory(Hanami.app.root) { assets_compile.call }
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def link_node_modules
|
|
61
|
-
root = Hanami.app.root
|
|
62
|
-
|
|
63
|
-
return if File.exist?(File.join(root, "node_modules", "hanami-assets", "dist", "hanami-assets.js"))
|
|
64
|
-
|
|
65
|
-
FileUtils.ln_s(node_modules_path, root)
|
|
66
|
-
rescue Errno::EEXIST # rubocop:disable Lint/SuppressedException
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def generate_assets_config
|
|
70
|
-
root = Hanami.app.root
|
|
71
|
-
|
|
72
|
-
with_directory(root) do
|
|
73
|
-
write("config/assets.js", <<~JS) unless root.join("config", "assets.js").exist?
|
|
74
|
-
import * as assets from "hanami-assets";
|
|
75
|
-
await assets.run();
|
|
76
|
-
JS
|
|
77
|
-
|
|
78
|
-
write("package.json", <<~JSON) unless root.join("package.json").exist?
|
|
79
|
-
{
|
|
80
|
-
"type": "module"
|
|
81
|
-
}
|
|
82
|
-
JSON
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
RSpec.shared_context "App integration" do
|
|
90
|
-
let(:app_modules) { %i[TestApp Admin Main Search] }
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def autoloaders_teardown!
|
|
94
|
-
ObjectSpace.each_object(Zeitwerk::Loader) do |loader|
|
|
95
|
-
loader.unregister if loader.dirs.any? { |dir|
|
|
96
|
-
dir.include?("/spec/") || dir.include?(Dir.tmpdir) ||
|
|
97
|
-
dir.include?("/slices/") || dir.include?("/app")
|
|
98
|
-
}
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
RSpec.configure do |config|
|
|
103
|
-
config.include RSpec::Support::Files, :app_integration
|
|
104
|
-
config.include RSpec::Support::WithTmpDirectory, :app_integration
|
|
105
|
-
config.include RSpec::Support::App, :app_integration
|
|
106
|
-
config.include_context "App integration", :app_integration
|
|
107
|
-
|
|
108
|
-
config.before :each, :app_integration do
|
|
109
|
-
# Conditionally assign these in case they have been assigned earlier for specific
|
|
110
|
-
# example groups (e.g. container/prepare_container_spec.rb)
|
|
111
|
-
@load_paths ||= $LOAD_PATH.dup
|
|
112
|
-
@loaded_features ||= $LOADED_FEATURES.dup
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
config.after :each, :app_integration do
|
|
116
|
-
autoloaders_teardown!
|
|
117
|
-
|
|
118
|
-
Hanami.instance_variable_set(:@_bundled, {})
|
|
119
|
-
Hanami.remove_instance_variable(:@_app) if Hanami.instance_variable_defined?(:@_app)
|
|
120
|
-
|
|
121
|
-
# Disconnect and clear cached DB gateways across slices
|
|
122
|
-
Hanami::Providers::DB.cache.values.map(&:disconnect)
|
|
123
|
-
Hanami::Providers::DB.cache.clear
|
|
124
|
-
|
|
125
|
-
$LOAD_PATH.replace(@load_paths)
|
|
126
|
-
|
|
127
|
-
# Remove example-specific LOADED_FEATURES added when running each example
|
|
128
|
-
new_features_to_keep = ($LOADED_FEATURES - @loaded_features).tap { |feats|
|
|
129
|
-
feats.delete_if do |path|
|
|
130
|
-
path =~ %r{hanami/(setup|prepare|boot|application/container/providers)} ||
|
|
131
|
-
path.include?(SPEC_ROOT.to_s) ||
|
|
132
|
-
path.include?(Dir.tmpdir)
|
|
133
|
-
end
|
|
134
|
-
}
|
|
135
|
-
$LOADED_FEATURES.replace(@loaded_features + new_features_to_keep)
|
|
136
|
-
|
|
137
|
-
app_modules.each do |app_module_name|
|
|
138
|
-
next unless Object.const_defined?(app_module_name)
|
|
139
|
-
|
|
140
|
-
Object.const_get(app_module_name).tap do |mod|
|
|
141
|
-
mod.constants.each do |name|
|
|
142
|
-
mod.send(:remove_const, name)
|
|
143
|
-
end
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
Object.send(:remove_const, app_module_name)
|
|
147
|
-
end
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
config.after :all do
|
|
151
|
-
if instance_variable_defined?(:@made_tmp_dirs)
|
|
152
|
-
Array(@made_tmp_dirs).each do |dir|
|
|
153
|
-
FileUtils.remove_entry dir
|
|
154
|
-
end
|
|
155
|
-
end
|
|
156
|
-
end
|
|
157
|
-
end
|
data/spec/support/coverage.rb
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
require "hanami/devtools/unit/support/coverage"
|
data/spec/support/matchers.rb
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RSpec
|
|
4
|
-
module Support
|
|
5
|
-
module Matchers
|
|
6
|
-
module HTML
|
|
7
|
-
def squish_html(str)
|
|
8
|
-
str
|
|
9
|
-
.gsub(/^[[:space:]]+/, "")
|
|
10
|
-
.gsub(/>[[:space:]]+</m, "><")
|
|
11
|
-
.strip
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
RSpec::Matchers.define :eq_html do |expected_html|
|
|
19
|
-
include RSpec::Support::Matchers::HTML
|
|
20
|
-
|
|
21
|
-
match do |actual_html|
|
|
22
|
-
squish_html(actual_html) == squish_html(expected_html)
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
RSpec::Matchers.define :include_html do |expected_html|
|
|
27
|
-
include RSpec::Support::Matchers::HTML
|
|
28
|
-
|
|
29
|
-
match do |actual_html|
|
|
30
|
-
squish_html(actual_html).include?(squish_html(expected_html))
|
|
31
|
-
end
|
|
32
|
-
end
|
data/spec/support/rspec.rb
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
RSpec.configure do |config|
|
|
4
|
-
config.expect_with :rspec do |expectations|
|
|
5
|
-
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
config.mock_with :rspec do |mocks|
|
|
9
|
-
mocks.verify_partial_doubles = true
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
config.before :suite do
|
|
13
|
-
require "hanami/devtools/integration"
|
|
14
|
-
Pathname.new(Dir.pwd).join("tmp").mkpath
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
config.shared_context_metadata_behavior = :apply_to_host_groups
|
|
18
|
-
|
|
19
|
-
config.filter_run_when_matching :focus
|
|
20
|
-
config.disable_monkey_patching!
|
|
21
|
-
config.warnings = false
|
|
22
|
-
|
|
23
|
-
config.default_formatter = "doc" if config.files_to_run.one?
|
|
24
|
-
|
|
25
|
-
config.order = :random
|
|
26
|
-
Kernel.srand config.seed
|
|
27
|
-
end
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "hanami/config/actions"
|
|
4
|
-
|
|
5
|
-
RSpec.describe Hanami::Config::Actions, "#content_security_policy" do
|
|
6
|
-
let(:app_config) { Hanami::Config.new(app_name: "MyApp::App", env: :development) }
|
|
7
|
-
let(:config) { app_config.actions }
|
|
8
|
-
subject(:content_security_policy) { config.content_security_policy }
|
|
9
|
-
|
|
10
|
-
context "no CSP config specified" do
|
|
11
|
-
it "has defaults" do
|
|
12
|
-
expect(content_security_policy[:base_uri]).to eq("'self'")
|
|
13
|
-
|
|
14
|
-
expected = [
|
|
15
|
-
%(base-uri 'self'),
|
|
16
|
-
%(child-src 'self'),
|
|
17
|
-
%(connect-src 'self'),
|
|
18
|
-
%(default-src 'none'),
|
|
19
|
-
%(font-src 'self'),
|
|
20
|
-
%(form-action 'self'),
|
|
21
|
-
%(frame-ancestors 'self'),
|
|
22
|
-
%(frame-src 'self'),
|
|
23
|
-
%(img-src 'self' https: data:),
|
|
24
|
-
%(media-src 'self'),
|
|
25
|
-
%(object-src 'none'),
|
|
26
|
-
%(script-src 'self'),
|
|
27
|
-
%(style-src 'self' 'unsafe-inline' https:)
|
|
28
|
-
].join(";")
|
|
29
|
-
|
|
30
|
-
expect(content_security_policy.to_s).to eq(expected)
|
|
31
|
-
expect(content_security_policy.nonce?).to be(false)
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
context "CSP settings specified" do
|
|
36
|
-
let(:cdn_url) { "https://assets.hanamirb.test" }
|
|
37
|
-
|
|
38
|
-
it "appends to default values" do
|
|
39
|
-
content_security_policy[:script_src] += " #{cdn_url}"
|
|
40
|
-
|
|
41
|
-
expect(content_security_policy[:script_src]).to eq("'self' #{cdn_url}")
|
|
42
|
-
expect(content_security_policy.to_s).to match("'self' #{cdn_url}")
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
it "overrides default values" do
|
|
46
|
-
content_security_policy[:style_src] = cdn_url
|
|
47
|
-
|
|
48
|
-
expect(content_security_policy[:style_src]).to eq(cdn_url)
|
|
49
|
-
expect(content_security_policy.to_s).to match(cdn_url)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
it "nullifies value" do
|
|
53
|
-
content_security_policy[:object_src] = nil
|
|
54
|
-
|
|
55
|
-
expect(content_security_policy[:object_src]).to be(nil)
|
|
56
|
-
expect(content_security_policy.to_s).to match("object-src ;")
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
it "deletes key" do
|
|
60
|
-
content_security_policy.delete(:object_src)
|
|
61
|
-
|
|
62
|
-
expect(content_security_policy[:object_src]).to be(nil)
|
|
63
|
-
expect(content_security_policy.to_s).to_not match("object-src")
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
it "adds a custom key" do
|
|
67
|
-
content_security_policy[:a_custom_key] = "foo"
|
|
68
|
-
|
|
69
|
-
expect(content_security_policy[:a_custom_key]).to eq("foo")
|
|
70
|
-
expect(content_security_policy.to_s).to match("a-custom-key foo")
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
it "uses 'nonce' in value" do
|
|
74
|
-
content_security_policy[:javascript_src] = "'self' 'nonce'"
|
|
75
|
-
|
|
76
|
-
expect(content_security_policy.nonce?).to be(true)
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
context "with CSP enabled" do
|
|
81
|
-
it "sets default header" do
|
|
82
|
-
app_config.finalize!
|
|
83
|
-
|
|
84
|
-
expect(config.default_headers.fetch("Content-Security-Policy")).to eq(content_security_policy.to_s)
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
context "with CSP disabled" do
|
|
89
|
-
it "doesn't set default header" do
|
|
90
|
-
config.content_security_policy = false
|
|
91
|
-
app_config.finalize!
|
|
92
|
-
|
|
93
|
-
expect(config.default_headers.key?("Content-Security-Policy")).to be(false)
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
end
|