hanami 2.1.0.beta1 → 2.1.0.beta2.1
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 +27 -4
- data/README.md +1 -1
- data/lib/hanami/app.rb +5 -0
- data/lib/hanami/config/actions.rb +4 -7
- data/lib/hanami/config/assets.rb +84 -0
- data/lib/hanami/config/null_config.rb +3 -0
- data/lib/hanami/config.rb +17 -5
- data/lib/hanami/extensions/action.rb +4 -2
- data/lib/hanami/extensions/view/standard_helpers.rb +4 -0
- data/lib/hanami/helpers/assets_helper.rb +772 -0
- data/lib/hanami/middleware/assets.rb +21 -0
- data/lib/hanami/middleware/render_errors.rb +4 -7
- 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 +25 -4
- data/lib/hanami/version.rb +1 -1
- data/lib/hanami.rb +2 -2
- 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 +4 -4
- data/spec/integration/rack_app/rack_app_spec.rb +0 -221
- data/spec/integration/rake_tasks_spec.rb +107 -0
- data/spec/integration/view/context/assets_spec.rb +3 -9
- data/spec/integration/web/render_detailed_errors_spec.rb +17 -0
- data/spec/integration/web/render_errors_spec.rb +6 -4
- data/spec/support/app_integration.rb +46 -2
- 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 -2
- data/spec/unit/hanami/env_spec.rb +11 -25
- data/spec/unit/hanami/helpers/assets_helper/asset_url_spec.rb +109 -0
- data/spec/unit/hanami/helpers/assets_helper/audio_spec.rb +136 -0
- data/spec/unit/hanami/helpers/assets_helper/favicon_spec.rb +91 -0
- data/spec/unit/hanami/helpers/assets_helper/image_spec.rb +96 -0
- data/spec/unit/hanami/helpers/assets_helper/javascript_spec.rb +147 -0
- data/spec/unit/hanami/helpers/assets_helper/stylesheet_spec.rb +130 -0
- data/spec/unit/hanami/helpers/assets_helper/video_spec.rb +136 -0
- data/spec/unit/hanami/version_spec.rb +1 -1
- metadata +32 -4
- data/lib/hanami/assets/app_config.rb +0 -61
- data/lib/hanami/assets/config.rb +0 -53
@@ -0,0 +1,128 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
require "rack/test"
|
5
|
+
require "stringio"
|
6
|
+
|
7
|
+
RSpec.describe "Logging / Request logging", :app_integration do
|
8
|
+
include Rack::Test::Methods
|
9
|
+
|
10
|
+
let(:app) { Hanami.app }
|
11
|
+
|
12
|
+
let(:logger_stream) { StringIO.new }
|
13
|
+
|
14
|
+
def configure_logger
|
15
|
+
Hanami.app.config.logger.stream = logger_stream
|
16
|
+
end
|
17
|
+
|
18
|
+
def logs
|
19
|
+
@logs ||= (logger_stream.rewind and logger_stream.read)
|
20
|
+
end
|
21
|
+
|
22
|
+
before do
|
23
|
+
with_directory(make_tmp_directory) do
|
24
|
+
write "config/app.rb", <<~RUBY
|
25
|
+
module TestApp
|
26
|
+
class App < Hanami::App
|
27
|
+
end
|
28
|
+
end
|
29
|
+
RUBY
|
30
|
+
|
31
|
+
require "hanami/setup"
|
32
|
+
configure_logger
|
33
|
+
|
34
|
+
before_prepare if respond_to?(:before_prepare)
|
35
|
+
require "hanami/prepare"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "app router" do
|
40
|
+
def before_prepare
|
41
|
+
write "config/routes.rb", <<~RUBY
|
42
|
+
module TestApp
|
43
|
+
class Routes < Hanami::Routes
|
44
|
+
root to: ->(env) { [200, {}, ["OK"]] }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
RUBY
|
48
|
+
end
|
49
|
+
|
50
|
+
it "logs the requests" do
|
51
|
+
get "/"
|
52
|
+
|
53
|
+
expect(logs.split("\n").length).to eq 1
|
54
|
+
expect(logs).to match %r{GET 200 \d+(µs|ms) 127.0.0.1 /}
|
55
|
+
end
|
56
|
+
|
57
|
+
context "production env" do
|
58
|
+
around do |example|
|
59
|
+
@prev_hanami_env = ENV["HANAMI_ENV"]
|
60
|
+
ENV["HANAMI_ENV"] = "production"
|
61
|
+
example.run
|
62
|
+
ensure
|
63
|
+
ENV["HANAMI_ENV"] = @prev_hanami_env
|
64
|
+
end
|
65
|
+
|
66
|
+
it "logs the requests as JSON" do
|
67
|
+
get "/"
|
68
|
+
|
69
|
+
expect(logs.split("\n").length).to eq 1
|
70
|
+
|
71
|
+
json = JSON.parse(logs, symbolize_names: true)
|
72
|
+
expect(json).to include(
|
73
|
+
verb: "GET",
|
74
|
+
path: "/",
|
75
|
+
ip: "127.0.0.1",
|
76
|
+
elapsed: Integer,
|
77
|
+
elapsed_unit: a_string_matching(/(µs|ms)/),
|
78
|
+
)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "slice router" do
|
84
|
+
let(:app) { Main::Slice.rack_app }
|
85
|
+
|
86
|
+
def before_prepare
|
87
|
+
write "slices/main/config/routes.rb", <<~RUBY
|
88
|
+
module Main
|
89
|
+
class Routes < Hanami::Routes
|
90
|
+
root to: ->(env) { [200, {}, ["OK"]] }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
RUBY
|
94
|
+
end
|
95
|
+
|
96
|
+
it "logs the requests" do
|
97
|
+
get "/"
|
98
|
+
|
99
|
+
expect(logs.split("\n").length).to eq 1
|
100
|
+
expect(logs).to match %r{GET 200 \d+(µs|ms) 127.0.0.1 /}
|
101
|
+
end
|
102
|
+
|
103
|
+
context "production env" do
|
104
|
+
around do |example|
|
105
|
+
@prev_hanami_env = ENV["HANAMI_ENV"]
|
106
|
+
ENV["HANAMI_ENV"] = "production"
|
107
|
+
example.run
|
108
|
+
ensure
|
109
|
+
ENV["HANAMI_ENV"] = @prev_hanami_env
|
110
|
+
end
|
111
|
+
|
112
|
+
it "logs the requests as JSON" do
|
113
|
+
get "/"
|
114
|
+
|
115
|
+
expect(logs.split("\n").length).to eq 1
|
116
|
+
|
117
|
+
json = JSON.parse(logs, symbolize_names: true)
|
118
|
+
expect(json).to include(
|
119
|
+
verb: "GET",
|
120
|
+
path: "/",
|
121
|
+
ip: "127.0.0.1",
|
122
|
+
elapsed: Integer,
|
123
|
+
elapsed_unit: a_string_matching(/(µs|ms)/),
|
124
|
+
)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -317,7 +317,7 @@ RSpec.describe "Hanami web app", :app_integration do
|
|
317
317
|
it "excludes not found routes in root scope" do
|
318
318
|
get "/foo"
|
319
319
|
|
320
|
-
expect(last_response.status).to eq
|
320
|
+
expect(last_response.status).to eq 404
|
321
321
|
expect(last_response.headers).to_not have_key("X-Auth-User-ID")
|
322
322
|
end
|
323
323
|
|
@@ -333,7 +333,7 @@ RSpec.describe "Hanami web app", :app_integration do
|
|
333
333
|
it "does not uses the Rack middleware for not found paths" do
|
334
334
|
get "/admin/users"
|
335
335
|
|
336
|
-
expect(last_response.status).to eq
|
336
|
+
expect(last_response.status).to eq 404
|
337
337
|
expect(last_response.headers).not_to have_key("X-Auth-User-ID")
|
338
338
|
end
|
339
339
|
end
|
@@ -600,7 +600,7 @@ RSpec.describe "Hanami web app", :app_integration do
|
|
600
600
|
it "does not use Rack middleware for other paths" do
|
601
601
|
get "/__not_found__"
|
602
602
|
|
603
|
-
expect(last_response.status).to eq
|
603
|
+
expect(last_response.status).to eq 404
|
604
604
|
expect(last_response.headers).not_to have_key("X-Identifier-Root")
|
605
605
|
expect(last_response.headers).not_to have_key("X-Elapsed")
|
606
606
|
expect(last_response.headers).not_to have_key("X-Auth-User-ID")
|
@@ -623,7 +623,7 @@ RSpec.describe "Hanami web app", :app_integration do
|
|
623
623
|
it "uses Rack middleware for other paths" do
|
624
624
|
get "/admin/__not_found__"
|
625
625
|
|
626
|
-
expect(last_response.status).to eq
|
626
|
+
expect(last_response.status).to eq 404
|
627
627
|
expect(last_response.headers).not_to have_key("X-Identifier-Admin")
|
628
628
|
expect(last_response.headers).not_to have_key("X-Elapsed")
|
629
629
|
expect(last_response.headers).not_to have_key("X-Elapsed")
|
@@ -33,227 +33,6 @@ RSpec.describe "Hanami web app", :app_integration do
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
specify "Has rack monitor preconfigured with default request logging" do
|
37
|
-
dir = Dir.mktmpdir
|
38
|
-
|
39
|
-
with_tmp_directory(dir) do
|
40
|
-
write "config/app.rb", <<~RUBY
|
41
|
-
require "hanami"
|
42
|
-
|
43
|
-
module TestApp
|
44
|
-
class App < Hanami::App
|
45
|
-
config.actions.format :json
|
46
|
-
config.logger.options = {colorize: true}
|
47
|
-
config.logger.stream = config.root.join("test.log")
|
48
|
-
end
|
49
|
-
end
|
50
|
-
RUBY
|
51
|
-
|
52
|
-
write "app/actions/users/index.rb", <<~RUBY
|
53
|
-
module TestApp
|
54
|
-
module Actions
|
55
|
-
module Users
|
56
|
-
class Index < Hanami::Action
|
57
|
-
def handle(req, _resp)
|
58
|
-
raise StandardError, "OH NOEZ"
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
RUBY
|
65
|
-
|
66
|
-
write "app/actions/users/create.rb", <<~RUBY
|
67
|
-
module TestApp
|
68
|
-
module Actions
|
69
|
-
module Users
|
70
|
-
class Create < Hanami::Action
|
71
|
-
def handle(req, resp)
|
72
|
-
resp.body = req.params.to_h.keys
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
RUBY
|
79
|
-
|
80
|
-
write "config/routes.rb", <<~RUBY
|
81
|
-
module TestApp
|
82
|
-
class Routes < Hanami::Routes
|
83
|
-
root to: ->(env) { [200, {}, ["OK"]] }
|
84
|
-
get "/users", to: "users.index"
|
85
|
-
post "/users", to: "users.create"
|
86
|
-
end
|
87
|
-
end
|
88
|
-
RUBY
|
89
|
-
|
90
|
-
require "hanami/prepare"
|
91
|
-
|
92
|
-
expect(Hanami.app["rack.monitor"]).to be_instance_of(Dry::Monitor::Rack::Middleware)
|
93
|
-
|
94
|
-
get "/"
|
95
|
-
|
96
|
-
logs = -> { Pathname(dir).join("test.log").realpath.read }
|
97
|
-
|
98
|
-
expect(logs.()).to match %r{GET 200 \d+(µs|ms) 127.0.0.1 /}
|
99
|
-
|
100
|
-
post "/users", JSON.generate(name: "jane", password: "secret"), {"CONTENT_TYPE" => "application/json"}
|
101
|
-
|
102
|
-
expect(logs.()).to match %r{POST 200 \d+(µs|ms) 127.0.0.1 /}
|
103
|
-
|
104
|
-
begin
|
105
|
-
get "/users"
|
106
|
-
rescue => e # rubocop:disable Style/RescueStandardError
|
107
|
-
raise unless e.to_s == "OH NOEZ"
|
108
|
-
end
|
109
|
-
|
110
|
-
err_log = logs.()
|
111
|
-
|
112
|
-
expect(err_log).to include("OH NOEZ")
|
113
|
-
expect(err_log).to include("app/actions/users/index.rb:6:in `handle'")
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
specify "Logging via the rack monitor even when notifications bus has already been used" do
|
118
|
-
dir = Dir.mktmpdir
|
119
|
-
|
120
|
-
with_tmp_directory(dir) do
|
121
|
-
write "config/app.rb", <<~RUBY
|
122
|
-
require "hanami"
|
123
|
-
|
124
|
-
module TestApp
|
125
|
-
class App < Hanami::App
|
126
|
-
config.actions.format :json
|
127
|
-
config.logger.options = {colorize: true}
|
128
|
-
config.logger.stream = config.root.join("test.log")
|
129
|
-
end
|
130
|
-
end
|
131
|
-
RUBY
|
132
|
-
|
133
|
-
write "config/routes.rb", <<~RUBY
|
134
|
-
module TestApp
|
135
|
-
class Routes < Hanami::Routes
|
136
|
-
post "/users", to: "users.create"
|
137
|
-
end
|
138
|
-
end
|
139
|
-
RUBY
|
140
|
-
|
141
|
-
write "app/actions/users/create.rb", <<~RUBY
|
142
|
-
module TestApp
|
143
|
-
module Actions
|
144
|
-
module Users
|
145
|
-
class Create < Hanami::Action
|
146
|
-
def handle(req, resp)
|
147
|
-
resp.body = req.params.to_h.keys
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
RUBY
|
154
|
-
|
155
|
-
require "hanami/prepare"
|
156
|
-
|
157
|
-
# Simulate any component interacting with the notifications bus such that it creates its
|
158
|
-
# internal bus with a duplicate copy of all currently registered events. This means that the
|
159
|
-
# class-level Dry::Monitor::Notification events implicitly registered by the
|
160
|
-
# Dry::Monitor::Rack::Middleware activated via the rack provider are ignored, unless our
|
161
|
-
# provider explicitly re-registers them on _instance_ of the notifications bus.
|
162
|
-
#
|
163
|
-
# See Hanami::Providers::Rack for more detail.
|
164
|
-
Hanami.app["notifications"].instrument(:sql)
|
165
|
-
|
166
|
-
logs = -> { Pathname(dir).join("test.log").realpath.read }
|
167
|
-
|
168
|
-
post "/users", JSON.generate(name: "jane", password: "secret"), {"CONTENT_TYPE" => "application/json"}
|
169
|
-
expect(logs.()).to match %r{POST 200 \d+(µs|ms) 127.0.0.1 /}
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
describe "Request logging when using slice router" do
|
174
|
-
let(:app) { Main::Slice.rack_app }
|
175
|
-
|
176
|
-
specify "Has rack monitor preconfigured with default request logging (when used via a slice)" do
|
177
|
-
dir = Dir.mktmpdir
|
178
|
-
|
179
|
-
with_tmp_directory(dir) do
|
180
|
-
write "config/app.rb", <<~RUBY
|
181
|
-
require "hanami"
|
182
|
-
|
183
|
-
module TestApp
|
184
|
-
class App < Hanami::App
|
185
|
-
config.logger.stream = config.root.join("test.log")
|
186
|
-
end
|
187
|
-
end
|
188
|
-
RUBY
|
189
|
-
|
190
|
-
write "slices/main/config/routes.rb", <<~RUBY
|
191
|
-
module Main
|
192
|
-
class Routes < Hanami::Routes
|
193
|
-
root to: ->(env) { [200, {}, ["OK"]] }
|
194
|
-
end
|
195
|
-
end
|
196
|
-
RUBY
|
197
|
-
|
198
|
-
require "hanami/prepare"
|
199
|
-
|
200
|
-
get "/"
|
201
|
-
|
202
|
-
logs = -> { Pathname(dir).join("test.log").realpath.read }
|
203
|
-
|
204
|
-
expect(logs.()).to match %r{GET 200 \d+(µs|ms) 127.0.0.1 /}
|
205
|
-
end
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
describe "Request logging on production" do
|
210
|
-
let(:app) { Main::Slice.rack_app }
|
211
|
-
|
212
|
-
around do |example|
|
213
|
-
@prev_hanami_env = ENV["HANAMI_ENV"]
|
214
|
-
ENV["HANAMI_ENV"] = "production"
|
215
|
-
example.run
|
216
|
-
ensure
|
217
|
-
ENV["HANAMI_ENV"] = @prev_hanami_env
|
218
|
-
end
|
219
|
-
|
220
|
-
specify "Has rack monitor preconfigured with default request logging (when used via a slice)" do
|
221
|
-
dir = Dir.mktmpdir
|
222
|
-
|
223
|
-
with_tmp_directory(dir) do
|
224
|
-
write "config/app.rb", <<~RUBY
|
225
|
-
require "hanami"
|
226
|
-
|
227
|
-
module TestApp
|
228
|
-
class App < Hanami::App
|
229
|
-
config.logger.stream = config.root.join("test.log")
|
230
|
-
end
|
231
|
-
end
|
232
|
-
RUBY
|
233
|
-
|
234
|
-
write "slices/main/config/routes.rb", <<~RUBY
|
235
|
-
module Main
|
236
|
-
class Routes < Hanami::Routes
|
237
|
-
root to: ->(env) { [200, {}, ["OK"]] }
|
238
|
-
end
|
239
|
-
end
|
240
|
-
RUBY
|
241
|
-
|
242
|
-
require "hanami/boot"
|
243
|
-
|
244
|
-
get "/"
|
245
|
-
|
246
|
-
logs = -> { Pathname(dir).join("test.log").realpath.read }
|
247
|
-
|
248
|
-
log_content = logs.()
|
249
|
-
|
250
|
-
expect(log_content).to match(%r["verb":"GET"])
|
251
|
-
expect(log_content).to match(%r["path":"/"])
|
252
|
-
expect(log_content).to match(%r[elapsed":\d+,"elapsed_unit":"µs"])
|
253
|
-
end
|
254
|
-
end
|
255
|
-
end
|
256
|
-
|
257
36
|
specify "Routing to actions based on their container identifiers" do
|
258
37
|
with_tmp_directory(Dir.mktmpdir) do
|
259
38
|
write "config/app.rb", <<~RUBY
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rake"
|
4
|
+
require "hanami/cli/bundler"
|
5
|
+
|
6
|
+
RSpec.describe "Rake tasks", :app_integration do
|
7
|
+
describe "assets:precompile" do
|
8
|
+
before do
|
9
|
+
allow(Hanami).to receive(:bundled?)
|
10
|
+
allow(Hanami).to receive(:bundled?).with("hanami-assets").and_return(hanami_assets_bundled)
|
11
|
+
end
|
12
|
+
|
13
|
+
context "when hanami-assets is bundled" do
|
14
|
+
let(:hanami_assets_bundled) { true }
|
15
|
+
|
16
|
+
xit "compiles assets" do
|
17
|
+
with_tmp_directory(Dir.mktmpdir) do
|
18
|
+
write "config/app.rb", <<~'RUBY'
|
19
|
+
require "hanami"
|
20
|
+
|
21
|
+
module TestApp
|
22
|
+
class App < Hanami::App
|
23
|
+
end
|
24
|
+
end
|
25
|
+
RUBY
|
26
|
+
|
27
|
+
write "Rakefile", <<~RUBY
|
28
|
+
# frozen_string_literal: true
|
29
|
+
|
30
|
+
require "hanami/rake_tasks"
|
31
|
+
RUBY
|
32
|
+
|
33
|
+
write "app/assets/js/app.js", <<~JS
|
34
|
+
console.log("Hello from index.js");
|
35
|
+
JS
|
36
|
+
|
37
|
+
before_prepare if respond_to?(:before_prepare)
|
38
|
+
require "hanami/prepare"
|
39
|
+
|
40
|
+
expect_any_instance_of(Hanami::CLI::Bundler).to receive(:hanami_exec).with("assets compile").and_return(true)
|
41
|
+
|
42
|
+
Rake::Task["assets:precompile"].invoke
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
it "doesn't list the task" do
|
47
|
+
with_tmp_directory(Dir.mktmpdir) do
|
48
|
+
write "config/app.rb", <<~'RUBY'
|
49
|
+
require "hanami"
|
50
|
+
|
51
|
+
module TestApp
|
52
|
+
class App < Hanami::App
|
53
|
+
end
|
54
|
+
end
|
55
|
+
RUBY
|
56
|
+
|
57
|
+
write "Rakefile", <<~RUBY
|
58
|
+
# frozen_string_literal: true
|
59
|
+
|
60
|
+
require "hanami/rake_tasks"
|
61
|
+
RUBY
|
62
|
+
|
63
|
+
before_prepare if respond_to?(:before_prepare)
|
64
|
+
require "hanami/prepare"
|
65
|
+
|
66
|
+
output = `bundle exec rake -T`
|
67
|
+
expect(output).to_not include("assets:precompile")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "when hanami-assets is not bundled" do
|
73
|
+
let(:hanami_assets_bundled) { false }
|
74
|
+
|
75
|
+
it "raises error" do
|
76
|
+
with_tmp_directory(Dir.mktmpdir) do
|
77
|
+
write "config/app.rb", <<~'RUBY'
|
78
|
+
require "hanami"
|
79
|
+
|
80
|
+
module TestApp
|
81
|
+
class App < Hanami::App
|
82
|
+
end
|
83
|
+
end
|
84
|
+
RUBY
|
85
|
+
|
86
|
+
write "Rakefile", <<~RUBY
|
87
|
+
# frozen_string_literal: true
|
88
|
+
|
89
|
+
require "hanami/rake_tasks"
|
90
|
+
RUBY
|
91
|
+
|
92
|
+
write "app/assets/js/app.js", <<~JS
|
93
|
+
console.log("Hello from index.js");
|
94
|
+
JS
|
95
|
+
|
96
|
+
before_prepare if respond_to?(:before_prepare)
|
97
|
+
require "hanami/prepare"
|
98
|
+
|
99
|
+
expect { Rake::Task["assets:precompile"].invoke }.to raise_error do |exception|
|
100
|
+
expect(exception).to be_a(RuntimeError)
|
101
|
+
expect(exception.message).to match(/Don't know how to build task 'assets:precompile'/)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -24,21 +24,15 @@ RSpec.describe "App view / Context / Assets", :app_integration do
|
|
24
24
|
|
25
25
|
describe "#assets" do
|
26
26
|
context "without assets provider" do
|
27
|
-
|
27
|
+
xit "raises error" do
|
28
|
+
allow(Hanami).to receive(:bundled?).with("hanami-assets").and_return(false)
|
29
|
+
|
28
30
|
expect { context.assets }
|
29
31
|
.to raise_error(Hanami::ComponentLoadError, /hanami-assets/)
|
30
32
|
end
|
31
33
|
end
|
32
34
|
|
33
35
|
context "with assets provider" do
|
34
|
-
before do
|
35
|
-
Hanami.app.register_provider(:assets) do
|
36
|
-
start do
|
37
|
-
register "assets", Object.new
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
36
|
it "is the app assets by default" do
|
43
37
|
expect(context.assets).to be TestApp::App[:assets]
|
44
38
|
end
|
@@ -56,6 +56,15 @@ RSpec.describe "Web / Rendering detailed errors", :app_integration do
|
|
56
56
|
expect(html).to have_selector("header", text: "RuntimeError at /error")
|
57
57
|
expect(html).to have_selector("ul.frames li.application", text: "app/actions/error.rb")
|
58
58
|
end
|
59
|
+
|
60
|
+
it "renders a detailed HTML error page and returns a 404 status for a not found error" do
|
61
|
+
get "/__not_found__", {}, "HTTP_ACCEPT" => "text/html"
|
62
|
+
|
63
|
+
expect(last_response.status).to eq 404
|
64
|
+
|
65
|
+
html = Capybara.string(last_response.body)
|
66
|
+
expect(html).to have_selector("header", text: "Hanami::Router::NotFoundError at /__not_found__")
|
67
|
+
end
|
59
68
|
end
|
60
69
|
|
61
70
|
describe "Other request types" do
|
@@ -67,6 +76,14 @@ RSpec.describe "Web / Rendering detailed errors", :app_integration do
|
|
67
76
|
expect(last_response.body).to include "RuntimeError at /error"
|
68
77
|
expect(last_response.body).to match %r{App backtrace.+app/actions/error.rb}m
|
69
78
|
end
|
79
|
+
|
80
|
+
it "renders a detailed error page in text and returns a 404 status for a not found error" do
|
81
|
+
get "/__not_found__", {}, "HTTP_ACCEPT" => "text/html"
|
82
|
+
|
83
|
+
expect(last_response.status).to eq 404
|
84
|
+
|
85
|
+
expect(last_response.body).to include "Hanami::Router::NotFoundError at /__not_found__"
|
86
|
+
end
|
70
87
|
end
|
71
88
|
|
72
89
|
describe "render_detailed_errors config disabled" do
|
@@ -225,12 +225,14 @@ RSpec.describe "Web / Rendering errors", :app_integration do
|
|
225
225
|
HTML
|
226
226
|
end
|
227
227
|
|
228
|
-
it "
|
229
|
-
|
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
|
230
231
|
end
|
231
232
|
|
232
|
-
it "
|
233
|
-
|
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
|
234
236
|
end
|
235
237
|
|
236
238
|
it "raises the original error for a 500" do
|
@@ -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
|