hanami 2.0.3 → 2.1.0.beta2
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 +37 -2
- data/LICENSE.md +1 -1
- data/README.md +26 -10
- data/hanami.gemspec +2 -2
- data/lib/hanami/app.rb +5 -0
- data/lib/hanami/config/actions.rb +4 -11
- data/lib/hanami/config/assets.rb +84 -0
- data/lib/hanami/config/null_config.rb +3 -0
- data/lib/hanami/config/views.rb +0 -4
- data/lib/hanami/config.rb +71 -5
- data/lib/hanami/extensions/action/slice_configured_action.rb +15 -7
- data/lib/hanami/extensions/action.rb +8 -6
- data/lib/hanami/extensions/router/errors.rb +58 -0
- data/lib/hanami/extensions/view/context.rb +129 -60
- data/lib/hanami/extensions/view/part.rb +26 -0
- data/lib/hanami/extensions/view/scope.rb +26 -0
- data/lib/hanami/extensions/view/slice_configured_context.rb +0 -2
- data/lib/hanami/extensions/view/slice_configured_helpers.rb +44 -0
- data/lib/hanami/extensions/view/slice_configured_view.rb +106 -21
- data/lib/hanami/extensions/view/standard_helpers.rb +18 -0
- data/lib/hanami/extensions.rb +10 -3
- data/lib/hanami/helpers/assets_helper.rb +752 -0
- data/lib/hanami/helpers/form_helper/form_builder.rb +1391 -0
- data/lib/hanami/helpers/form_helper/values.rb +75 -0
- data/lib/hanami/helpers/form_helper.rb +213 -0
- data/lib/hanami/middleware/assets.rb +21 -0
- data/lib/hanami/middleware/public_errors_app.rb +75 -0
- data/lib/hanami/middleware/render_errors.rb +90 -0
- data/lib/hanami/providers/assets.rb +44 -0
- data/lib/hanami/rake_tasks.rb +19 -18
- data/lib/hanami/settings.rb +1 -1
- data/lib/hanami/slice.rb +48 -2
- data/lib/hanami/slice_configurable.rb +3 -2
- data/lib/hanami/version.rb +1 -1
- data/lib/hanami/web/rack_logger.rb +1 -1
- data/lib/hanami.rb +3 -3
- data/spec/integration/action/view_rendering/view_context_spec.rb +221 -0
- data/spec/integration/action/view_rendering_spec.rb +0 -18
- data/spec/integration/assets/assets_spec.rb +101 -0
- data/spec/integration/assets/serve_static_assets_spec.rb +152 -0
- data/spec/integration/logging/exception_logging_spec.rb +115 -0
- data/spec/integration/logging/notifications_spec.rb +68 -0
- data/spec/integration/logging/request_logging_spec.rb +128 -0
- data/spec/integration/rack_app/middleware_spec.rb +22 -22
- data/spec/integration/rack_app/rack_app_spec.rb +3 -220
- data/spec/integration/rake_tasks_spec.rb +107 -0
- data/spec/integration/view/config/default_context_spec.rb +149 -0
- data/spec/integration/view/{inflector_spec.rb → config/inflector_spec.rb} +1 -1
- data/spec/integration/view/config/part_class_spec.rb +147 -0
- data/spec/integration/view/config/part_namespace_spec.rb +103 -0
- data/spec/integration/view/config/paths_spec.rb +119 -0
- data/spec/integration/view/config/scope_class_spec.rb +147 -0
- data/spec/integration/view/config/scope_namespace_spec.rb +103 -0
- data/spec/integration/view/config/template_spec.rb +38 -0
- data/spec/integration/view/context/assets_spec.rb +3 -9
- data/spec/integration/view/context/request_spec.rb +3 -7
- data/spec/integration/view/helpers/form_helper_spec.rb +174 -0
- data/spec/integration/view/helpers/part_helpers_spec.rb +124 -0
- data/spec/integration/view/helpers/scope_helpers_spec.rb +84 -0
- data/spec/integration/view/helpers/user_defined_helpers/part_helpers_spec.rb +162 -0
- data/spec/integration/view/helpers/user_defined_helpers/scope_helpers_spec.rb +119 -0
- data/spec/integration/view/slice_configuration_spec.rb +9 -9
- data/spec/integration/web/render_detailed_errors_spec.rb +107 -0
- data/spec/integration/web/render_errors_spec.rb +242 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/support/app_integration.rb +46 -2
- data/spec/support/matchers.rb +32 -0
- data/spec/unit/hanami/config/actions/content_security_policy_spec.rb +24 -36
- data/spec/unit/hanami/config/actions/csrf_protection_spec.rb +4 -3
- data/spec/unit/hanami/config/actions/default_values_spec.rb +3 -6
- data/spec/unit/hanami/config/render_detailed_errors_spec.rb +25 -0
- data/spec/unit/hanami/config/render_errors_spec.rb +25 -0
- data/spec/unit/hanami/config/views_spec.rb +0 -18
- data/spec/unit/hanami/env_spec.rb +11 -25
- data/spec/unit/hanami/extensions/view/context_spec.rb +59 -0
- data/spec/unit/hanami/helpers/assets_helper/asset_url_spec.rb +109 -0
- data/spec/unit/hanami/helpers/assets_helper/audio_tag_spec.rb +132 -0
- data/spec/unit/hanami/helpers/assets_helper/favicon_link_tag_spec.rb +91 -0
- data/spec/unit/hanami/helpers/assets_helper/image_tag_spec.rb +92 -0
- data/spec/unit/hanami/helpers/assets_helper/javascript_tag_spec.rb +143 -0
- data/spec/unit/hanami/helpers/assets_helper/stylesheet_link_tag_spec.rb +126 -0
- data/spec/unit/hanami/helpers/assets_helper/video_tag_spec.rb +132 -0
- data/spec/unit/hanami/helpers/form_helper_spec.rb +2826 -0
- data/spec/unit/hanami/router/errors/not_allowed_error_spec.rb +27 -0
- data/spec/unit/hanami/router/errors/not_found_error_spec.rb +22 -0
- data/spec/unit/hanami/slice_configurable_spec.rb +18 -0
- data/spec/unit/hanami/version_spec.rb +1 -1
- data/spec/unit/hanami/web/rack_logger_spec.rb +1 -1
- metadata +95 -35
- data/lib/hanami/assets/app_config.rb +0 -61
- data/lib/hanami/assets/config.rb +0 -53
- data/spec/integration/action/view_integration_spec.rb +0 -165
- data/spec/integration/view/part_namespace_spec.rb +0 -96
- data/spec/integration/view/path_spec.rb +0 -56
- data/spec/integration/view/template_spec.rb +0 -68
- data/spec/isolation/hanami/application/already_configured_spec.rb +0 -19
- data/spec/isolation/hanami/application/inherit_anonymous_class_spec.rb +0 -10
- data/spec/isolation/hanami/application/inherit_concrete_class_spec.rb +0 -14
- data/spec/isolation/hanami/application/not_configured_spec.rb +0 -9
- data/spec/isolation/hanami/application/routes/configured_spec.rb +0 -44
- data/spec/isolation/hanami/application/routes/not_configured_spec.rb +0 -16
- data/spec/isolation/hanami/boot/success_spec.rb +0 -50
|
@@ -0,0 +1,242 @@
|
|
|
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
|
data/spec/spec_helper.rb
CHANGED
|
@@ -23,6 +23,6 @@ RSpec.configure do |config|
|
|
|
23
23
|
# TODO: Find out what causes logger to create this dir when running specs.
|
|
24
24
|
# There's probably a test app class being created somewhere with root
|
|
25
25
|
# not pointing to a tmp dir.
|
|
26
|
-
FileUtils.
|
|
26
|
+
FileUtils.rm_rf(LOG_DIR) if LOG_DIR.exist?
|
|
27
27
|
end
|
|
28
28
|
end
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "hanami/devtools/integration/files"
|
|
4
4
|
require "hanami/devtools/integration/with_tmp_directory"
|
|
5
|
+
require "json"
|
|
5
6
|
require "tmpdir"
|
|
6
7
|
require "zeitwerk"
|
|
7
8
|
|
|
@@ -16,10 +17,52 @@ module RSpec
|
|
|
16
17
|
end
|
|
17
18
|
end
|
|
18
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
|
+
def stub_assets(*assets)
|
|
33
|
+
manifest_hash = assets.each_with_object({}) { |source_path, hsh|
|
|
34
|
+
hsh[source_path] = {url: File.join("/assets", source_path)}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
write "public/assets.json", JSON.generate(manifest_hash)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def compile_assets!
|
|
41
|
+
link_node_modules
|
|
42
|
+
|
|
43
|
+
require "hanami/cli/command"
|
|
44
|
+
require "hanami/cli/commands/app/command"
|
|
45
|
+
require "hanami/cli/commands/app/assets/compile"
|
|
46
|
+
compiler = Hanami::CLI::Commands::App::Assets::Compile.new(config: Hanami.app.config.assets)
|
|
47
|
+
|
|
48
|
+
with_directory(Hanami.app.root) do
|
|
49
|
+
compiler.call
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def link_node_modules
|
|
54
|
+
root = Hanami.app.root
|
|
55
|
+
|
|
56
|
+
return if File.exist?(File.join(root, "node_modules", "hanami-assets", "dist", "hanami-assets.js"))
|
|
57
|
+
|
|
58
|
+
FileUtils.ln_s(node_modules_path, root)
|
|
59
|
+
rescue Errno::EEXIST # rubocop:disable Lint/SuppressedException
|
|
60
|
+
end
|
|
61
|
+
end
|
|
19
62
|
end
|
|
20
63
|
end
|
|
21
64
|
|
|
22
|
-
RSpec.shared_context "
|
|
65
|
+
RSpec.shared_context "App integration" do
|
|
23
66
|
let(:app_modules) { %i[TestApp Admin Main Search] }
|
|
24
67
|
end
|
|
25
68
|
|
|
@@ -35,7 +78,8 @@ end
|
|
|
35
78
|
RSpec.configure do |config|
|
|
36
79
|
config.include RSpec::Support::Files, :app_integration
|
|
37
80
|
config.include RSpec::Support::WithTmpDirectory, :app_integration
|
|
38
|
-
config.
|
|
81
|
+
config.include RSpec::Support::App, :app_integration
|
|
82
|
+
config.include_context "App integration", :app_integration
|
|
39
83
|
|
|
40
84
|
config.before :each, :app_integration do
|
|
41
85
|
# Conditionally assign these in case they have been assigned earlier for specific
|
|
@@ -0,0 +1,32 @@
|
|
|
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
|
|
@@ -3,43 +3,31 @@
|
|
|
3
3
|
require "hanami/config/actions"
|
|
4
4
|
|
|
5
5
|
RSpec.describe Hanami::Config::Actions, "#content_security_policy" do
|
|
6
|
-
let(:
|
|
6
|
+
let(:app_config) { Hanami::Config.new(app_name: "MyApp::App", env: :development) }
|
|
7
|
+
let(:config) { app_config.actions }
|
|
7
8
|
subject(:content_security_policy) { config.content_security_policy }
|
|
8
9
|
|
|
9
10
|
context "no CSP config specified" do
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
expect(content_security_policy.to_s).to eq(expected)
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
context "with assets_server_url" do
|
|
36
|
-
let(:config) { described_class.new(assets_server_url: assets_server_url) }
|
|
37
|
-
let(:assets_server_url) { "http://localhost:8080" }
|
|
38
|
-
|
|
39
|
-
it "includes server url" do
|
|
40
|
-
expect(content_security_policy[:script_src]).to eq("'self' #{assets_server_url}")
|
|
41
|
-
expect(content_security_policy[:style_src]).to eq("'self' 'unsafe-inline' https: #{assets_server_url}")
|
|
42
|
-
end
|
|
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)
|
|
43
31
|
end
|
|
44
32
|
end
|
|
45
33
|
|
|
@@ -84,7 +72,7 @@ RSpec.describe Hanami::Config::Actions, "#content_security_policy" do
|
|
|
84
72
|
|
|
85
73
|
context "with CSP enabled" do
|
|
86
74
|
it "sets default header" do
|
|
87
|
-
|
|
75
|
+
app_config.finalize!
|
|
88
76
|
|
|
89
77
|
expect(config.default_headers.fetch("Content-Security-Policy")).to eq(content_security_policy.to_s)
|
|
90
78
|
end
|
|
@@ -93,7 +81,7 @@ RSpec.describe Hanami::Config::Actions, "#content_security_policy" do
|
|
|
93
81
|
context "with CSP disabled" do
|
|
94
82
|
it "doesn't set default header" do
|
|
95
83
|
config.content_security_policy = false
|
|
96
|
-
|
|
84
|
+
app_config.finalize!
|
|
97
85
|
|
|
98
86
|
expect(config.default_headers.key?("Content-Security-Policy")).to be(false)
|
|
99
87
|
end
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
require "hanami/config/actions"
|
|
4
4
|
|
|
5
5
|
RSpec.describe Hanami::Config::Actions, "#csrf_protection" do
|
|
6
|
-
let(:
|
|
6
|
+
let(:app_config) { Hanami::Config.new(app_name: "MyApp::App", env: :development) }
|
|
7
|
+
let(:config) { app_config.actions }
|
|
7
8
|
subject(:value) { config.csrf_protection }
|
|
8
9
|
|
|
9
10
|
context "non-finalized config" do
|
|
@@ -26,7 +27,7 @@ RSpec.describe Hanami::Config::Actions, "#csrf_protection" do
|
|
|
26
27
|
context "sessions enabled" do
|
|
27
28
|
before do
|
|
28
29
|
config.sessions = :cookie, {secret: "abc"}
|
|
29
|
-
|
|
30
|
+
app_config.finalize!
|
|
30
31
|
end
|
|
31
32
|
|
|
32
33
|
it "is true" do
|
|
@@ -46,7 +47,7 @@ RSpec.describe Hanami::Config::Actions, "#csrf_protection" do
|
|
|
46
47
|
|
|
47
48
|
context "sessions not enabled" do
|
|
48
49
|
before do
|
|
49
|
-
|
|
50
|
+
app_config.finalize!
|
|
50
51
|
end
|
|
51
52
|
|
|
52
53
|
it "is true" do
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
require "hanami/config/actions"
|
|
4
4
|
|
|
5
5
|
RSpec.describe Hanami::Config::Actions, "default values" do
|
|
6
|
-
|
|
6
|
+
let(:app_config) { Hanami::Config.new(app_name: "MyApp::App", env: :development) }
|
|
7
|
+
subject(:config) { app_config.actions }
|
|
7
8
|
|
|
8
9
|
describe "sessions" do
|
|
9
10
|
specify { expect(config.sessions).not_to be_enabled }
|
|
@@ -13,10 +14,6 @@ RSpec.describe Hanami::Config::Actions, "default values" do
|
|
|
13
14
|
specify { expect(config.name_inference_base).to eq "actions" }
|
|
14
15
|
end
|
|
15
16
|
|
|
16
|
-
describe "view_context_identifier" do
|
|
17
|
-
specify { expect(config.view_context_identifier).to eq "views.context" }
|
|
18
|
-
end
|
|
19
|
-
|
|
20
17
|
describe "view_name_inferrer" do
|
|
21
18
|
specify { expect(config.view_name_inferrer).to eq Hanami::Slice::ViewNameInferrer }
|
|
22
19
|
end
|
|
@@ -32,7 +29,7 @@ RSpec.describe Hanami::Config::Actions, "default values" do
|
|
|
32
29
|
|
|
33
30
|
describe "default_headers" do
|
|
34
31
|
specify {
|
|
35
|
-
|
|
32
|
+
app_config.finalize!
|
|
36
33
|
|
|
37
34
|
expect(config.default_headers).to eq(
|
|
38
35
|
"X-Frame-Options" => "DENY",
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dry/inflector"
|
|
4
|
+
|
|
5
|
+
RSpec.describe Hanami::Config, "#render_detailed_errors" do
|
|
6
|
+
let(:config) { described_class.new(app_name: app_name, env: env) }
|
|
7
|
+
let(:app_name) { Hanami::SliceName.new(double(name: "MyApp::App"), inflector: Dry::Inflector.new) }
|
|
8
|
+
|
|
9
|
+
subject(:render_detailed_errors) { config.render_detailed_errors }
|
|
10
|
+
|
|
11
|
+
context "development mode" do
|
|
12
|
+
let(:env) { :development }
|
|
13
|
+
it { is_expected.to be true }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
context "test mode" do
|
|
17
|
+
let(:env) { :test }
|
|
18
|
+
it { is_expected.to be true }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
context "production mode" do
|
|
22
|
+
let(:env) { :production }
|
|
23
|
+
it { is_expected.to be false }
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dry/inflector"
|
|
4
|
+
|
|
5
|
+
RSpec.describe Hanami::Config, "#render_errors" do
|
|
6
|
+
let(:config) { described_class.new(app_name: app_name, env: env) }
|
|
7
|
+
let(:app_name) { Hanami::SliceName.new(double(name: "MyApp::App"), inflector: Dry::Inflector.new) }
|
|
8
|
+
|
|
9
|
+
subject(:render_errors) { config.render_errors }
|
|
10
|
+
|
|
11
|
+
context "development mode" do
|
|
12
|
+
let(:env) { :development }
|
|
13
|
+
it { is_expected.to be false }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
context "test mode" do
|
|
17
|
+
let(:env) { :test }
|
|
18
|
+
it { is_expected.to be false }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
context "production mode" do
|
|
22
|
+
let(:env) { :production }
|
|
23
|
+
it { is_expected.to be true }
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -39,20 +39,6 @@ RSpec.describe Hanami::Config, "#views" do
|
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
describe "specialised default values" do
|
|
42
|
-
describe "paths" do
|
|
43
|
-
it 'is ["templates"]' do
|
|
44
|
-
expect(views.paths).to match [
|
|
45
|
-
an_object_satisfying { |path| path.dir.to_s == "templates" }
|
|
46
|
-
]
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
describe "template_inference_base" do
|
|
51
|
-
it 'is "views"' do
|
|
52
|
-
expect(views.template_inference_base).to eq "views"
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
42
|
describe "layout" do
|
|
57
43
|
it 'is "app"' do
|
|
58
44
|
expect(views.layout).to eq "app"
|
|
@@ -69,10 +55,6 @@ RSpec.describe Hanami::Config, "#views" do
|
|
|
69
55
|
expect(views).to be_frozen
|
|
70
56
|
end
|
|
71
57
|
|
|
72
|
-
it "does not allow changes to locally defined settings" do
|
|
73
|
-
expect { views.parts_path = "parts" }.to raise_error(Dry::Configurable::FrozenConfigError)
|
|
74
|
-
end
|
|
75
|
-
|
|
76
58
|
it "does not allow changes to base view settings" do
|
|
77
59
|
expect { views.paths = [] }.to raise_error(Dry::Configurable::FrozenConfigError)
|
|
78
60
|
end
|
|
@@ -1,54 +1,40 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
RSpec.describe Hanami, ".env" do
|
|
4
|
-
subject
|
|
5
|
-
|
|
6
|
-
before do
|
|
7
|
-
@orig_env = ENV.to_h
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
after do
|
|
11
|
-
ENV.replace(@orig_env)
|
|
12
|
-
end
|
|
4
|
+
subject { described_class.env(e: env) }
|
|
13
5
|
|
|
14
6
|
context "HANAMI_ENV in ENV" do
|
|
15
|
-
|
|
16
|
-
ENV["HANAMI_ENV"] = "test"
|
|
17
|
-
end
|
|
7
|
+
let(:env) { {"HANAMI_ENV" => "test"} }
|
|
18
8
|
|
|
19
9
|
it "is the value of HANAMI_ENV" do
|
|
20
|
-
is_expected.to eq
|
|
10
|
+
is_expected.to eq(:test)
|
|
21
11
|
end
|
|
22
12
|
end
|
|
23
13
|
|
|
24
14
|
context "RACK_ENV in ENV" do
|
|
25
|
-
|
|
26
|
-
ENV["RACK_ENV"] = "test"
|
|
27
|
-
end
|
|
15
|
+
let(:env) { {"HANAMI_ENV" => "test"} }
|
|
28
16
|
|
|
29
17
|
it "is the value of RACK_ENV" do
|
|
30
|
-
is_expected.to eq
|
|
18
|
+
is_expected.to eq(:test)
|
|
31
19
|
end
|
|
32
20
|
end
|
|
33
21
|
|
|
34
22
|
context "both HANAMI_ENV and RACK_ENV in ENV" do
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
23
|
+
let(:env) do
|
|
24
|
+
{"HANAMI_ENV" => "test",
|
|
25
|
+
"RACK_ENV" => "production"}
|
|
38
26
|
end
|
|
39
27
|
|
|
40
28
|
it "is the value of HANAMI_ENV" do
|
|
41
|
-
is_expected.to eq
|
|
29
|
+
is_expected.to eq(:test)
|
|
42
30
|
end
|
|
43
31
|
end
|
|
44
32
|
|
|
45
33
|
context "no ENV vars set" do
|
|
46
|
-
|
|
47
|
-
ENV.delete("HANAMI_ENV")
|
|
48
|
-
end
|
|
34
|
+
let(:env) { {} }
|
|
49
35
|
|
|
50
36
|
it "defaults to \"development\"" do
|
|
51
|
-
is_expected.to eq
|
|
37
|
+
is_expected.to eq(:development)
|
|
52
38
|
end
|
|
53
39
|
end
|
|
54
40
|
end
|