hanami 2.0.0.beta4 → 2.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 +19 -0
- data/hanami.gemspec +8 -7
- data/lib/hanami/app.rb +47 -36
- data/lib/hanami/assets/app_config.rb +7 -15
- data/lib/hanami/assets/config.rb +5 -6
- data/lib/hanami/config/actions/content_security_policy.rb +1 -1
- data/lib/hanami/config/actions/cookies.rb +27 -0
- data/lib/hanami/config/actions/sessions.rb +42 -5
- data/lib/hanami/config/actions.rb +81 -17
- data/lib/hanami/config/logger.rb +112 -23
- data/lib/hanami/config/router.rb +0 -1
- data/lib/hanami/config/views.rb +6 -10
- data/lib/hanami/config.rb +235 -73
- data/lib/hanami/constants.rb +4 -0
- data/lib/hanami/errors.rb +17 -0
- data/lib/hanami/extensions/action/slice_configured_action.rb +9 -5
- data/lib/hanami/extensions/action.rb +59 -7
- data/lib/hanami/extensions/view/context.rb +3 -4
- data/lib/hanami/extensions/view/slice_configured_view.rb +4 -4
- data/lib/hanami/extensions/view.rb +7 -5
- data/lib/hanami/providers/inflector.rb +6 -0
- data/lib/hanami/providers/logger.rb +8 -0
- data/lib/hanami/providers/rack.rb +12 -0
- data/lib/hanami/providers/routes.rb +14 -4
- data/lib/hanami/routes.rb +36 -1
- data/lib/hanami/settings/env_store.rb +1 -1
- data/lib/hanami/settings.rb +102 -36
- data/lib/hanami/slice/router.rb +38 -16
- data/lib/hanami/slice/routing/middleware/stack.rb +66 -42
- data/lib/hanami/slice/routing/resolver.rb +10 -17
- data/lib/hanami/slice/view_name_inferrer.rb +1 -1
- data/lib/hanami/slice.rb +553 -14
- data/lib/hanami/slice_registrar.rb +20 -15
- data/lib/hanami/version.rb +2 -3
- data/lib/hanami/web/rack_logger.rb +14 -4
- data/lib/hanami.rb +122 -23
- data/spec/integration/action/csrf_protection_spec.rb +1 -1
- data/spec/integration/container/application_routes_helper_spec.rb +3 -1
- data/spec/integration/container/provider_lifecycle_spec.rb +61 -0
- data/spec/integration/container/standard_providers/rack_provider_spec.rb +44 -0
- data/spec/integration/container/{standard_bootable_components_spec.rb → standard_providers_spec.rb} +3 -3
- data/spec/integration/rack_app/body_parser_spec.rb +3 -0
- data/spec/integration/rack_app/middleware_spec.rb +427 -3
- data/spec/integration/rack_app/non_booted_rack_app_spec.rb +2 -1
- data/spec/integration/rack_app/rack_app_spec.rb +39 -11
- data/spec/integration/setup_spec.rb +4 -4
- data/spec/integration/slices/external_slice_spec.rb +2 -1
- data/spec/integration/slices/slice_configuration_spec.rb +3 -1
- data/spec/integration/slices/slice_loading_spec.rb +4 -4
- data/spec/integration/slices/slice_routing_spec.rb +4 -3
- data/spec/integration/slices_spec.rb +100 -0
- data/spec/isolation/hanami/boot/success_spec.rb +1 -1
- data/spec/support/app_integration.rb +2 -10
- data/spec/unit/hanami/config/actions/content_security_policy_spec.rb +7 -7
- data/spec/unit/hanami/config/actions/default_values_spec.rb +1 -1
- data/spec/unit/hanami/config/actions/sessions_spec.rb +1 -3
- data/spec/unit/hanami/config/actions_spec.rb +1 -12
- data/spec/unit/hanami/config/logger_spec.rb +38 -55
- data/spec/unit/hanami/config/router_spec.rb +1 -1
- data/spec/unit/hanami/config/views_spec.rb +3 -13
- data/spec/unit/hanami/settings_spec.rb +1 -1
- data/spec/unit/hanami/slice_configurable_spec.rb +5 -5
- data/spec/unit/hanami/slice_spec.rb +32 -0
- data/spec/unit/hanami/version_spec.rb +1 -1
- data/spec/unit/hanami/web/rack_logger_spec.rb +13 -2
- metadata +54 -45
- data/lib/hanami/config/sessions.rb +0 -50
- data/spec/unit/hanami/config_spec.rb +0 -43
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "rack/test"
|
4
|
+
require "stringio"
|
4
5
|
|
5
6
|
RSpec.describe "Hanami web app", :app_integration do
|
6
7
|
include Rack::Test::Methods
|
@@ -50,7 +51,7 @@ RSpec.describe "Hanami web app", :app_integration do
|
|
50
51
|
|
51
52
|
module TestApp
|
52
53
|
class App < Hanami::App
|
53
|
-
config.logger.stream =
|
54
|
+
config.logger.stream = StringIO.new
|
54
55
|
|
55
56
|
config.middleware.use Middlewares::AppendOne
|
56
57
|
config.middleware.use Middlewares::Prepare, before: Middlewares::AppendOne
|
@@ -101,7 +102,7 @@ RSpec.describe "Hanami web app", :app_integration do
|
|
101
102
|
|
102
103
|
module TestApp
|
103
104
|
class App < Hanami::App
|
104
|
-
config.logger.stream =
|
105
|
+
config.logger.stream = StringIO.new
|
105
106
|
end
|
106
107
|
end
|
107
108
|
RUBY
|
@@ -164,7 +165,7 @@ RSpec.describe "Hanami web app", :app_integration do
|
|
164
165
|
end
|
165
166
|
|
166
167
|
class App < Hanami::App
|
167
|
-
config.logger.stream =
|
168
|
+
config.logger.stream = StringIO.new
|
168
169
|
|
169
170
|
config.middleware.use(TestApp::TestMiddleware) { |env| env["tested"] = "yes" }
|
170
171
|
end
|
@@ -234,4 +235,427 @@ RSpec.describe "Hanami web app", :app_integration do
|
|
234
235
|
}.to raise_error(Hanami::UnsupportedMiddlewareSpecError)
|
235
236
|
end
|
236
237
|
end
|
238
|
+
|
239
|
+
context "with simple app" do
|
240
|
+
before do
|
241
|
+
write "config/app.rb", <<~RUBY
|
242
|
+
require "hanami"
|
243
|
+
|
244
|
+
module TestApp
|
245
|
+
class App < Hanami::App
|
246
|
+
config.logger.stream = File.new("/dev/null", "w")
|
247
|
+
end
|
248
|
+
end
|
249
|
+
RUBY
|
250
|
+
|
251
|
+
write "lib/test_app/middleware/authentication.rb", <<~RUBY
|
252
|
+
module TestApp
|
253
|
+
module Middleware
|
254
|
+
class Authentication
|
255
|
+
def self.inspect
|
256
|
+
"<Middleware::Auth>"
|
257
|
+
end
|
258
|
+
|
259
|
+
def initialize(app)
|
260
|
+
@app = app
|
261
|
+
end
|
262
|
+
|
263
|
+
def call(env)
|
264
|
+
env["AUTH_USER_ID"] = user_id = "23"
|
265
|
+
status, headers, body = @app.call(env)
|
266
|
+
headers["X-Auth-User-ID"] = user_id
|
267
|
+
|
268
|
+
[status, headers, body]
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
RUBY
|
274
|
+
|
275
|
+
write "config/routes.rb", <<~RUBY
|
276
|
+
require "test_app/middleware/authentication"
|
277
|
+
|
278
|
+
module TestApp
|
279
|
+
class Routes < Hanami::Routes
|
280
|
+
root to: ->(*) { [200, {"Content-Length" => "4"}, ["Home"]] }
|
281
|
+
|
282
|
+
slice :admin, at: "/admin" do
|
283
|
+
use TestApp::Middleware::Authentication
|
284
|
+
|
285
|
+
root to: "home.show"
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
RUBY
|
290
|
+
|
291
|
+
write "slices/admin/actions/home/show.rb", <<~RUBY
|
292
|
+
module Admin
|
293
|
+
module Actions
|
294
|
+
module Home
|
295
|
+
class Show < Hanami::Action
|
296
|
+
def handle(req, res)
|
297
|
+
res.body = "Hello from admin (User ID " + req.env['AUTH_USER_ID'] + ")"
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
RUBY
|
304
|
+
|
305
|
+
require "hanami/boot"
|
306
|
+
end
|
307
|
+
|
308
|
+
it "excludes root scope" do
|
309
|
+
get "/"
|
310
|
+
|
311
|
+
expect(last_response.status).to eq 200
|
312
|
+
expect(last_response.body).to eq "Home"
|
313
|
+
expect(last_response.headers).to_not have_key("X-Auth-User-ID")
|
314
|
+
end
|
315
|
+
|
316
|
+
it "excludes not found routes in root scope" do
|
317
|
+
get "/foo"
|
318
|
+
|
319
|
+
expect(last_response.status).to eq 404
|
320
|
+
expect(last_response.body).to eq "Not Found"
|
321
|
+
expect(last_response.headers).to_not have_key("X-Auth-User-ID")
|
322
|
+
end
|
323
|
+
|
324
|
+
context "within slice" do
|
325
|
+
it "uses Rack middleware" do
|
326
|
+
get "/admin"
|
327
|
+
|
328
|
+
expect(last_response.status).to eq 200
|
329
|
+
expect(last_response.body).to eq "Hello from admin (User ID 23)"
|
330
|
+
expect(last_response.headers).to have_key("X-Auth-User-ID")
|
331
|
+
end
|
332
|
+
|
333
|
+
it "uses Rack middleware for not found paths" do
|
334
|
+
get "/admin/users"
|
335
|
+
|
336
|
+
expect(last_response.status).to be(404)
|
337
|
+
expect(last_response.body).to eq "Not Found"
|
338
|
+
expect(last_response.headers).to have_key("X-Auth-User-ID")
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
context "with complex app" do
|
344
|
+
let(:app_modules) { %i[TestApp Admin APIV1] }
|
345
|
+
|
346
|
+
before do
|
347
|
+
write "config/app.rb", <<~RUBY
|
348
|
+
require "hanami"
|
349
|
+
|
350
|
+
module TestApp
|
351
|
+
class App < Hanami::App
|
352
|
+
config.logger.stream = File.new("/dev/null", "w")
|
353
|
+
end
|
354
|
+
end
|
355
|
+
RUBY
|
356
|
+
|
357
|
+
write "lib/test_app/middleware/elapsed.rb", <<~RUBY
|
358
|
+
module TestApp
|
359
|
+
module Middleware
|
360
|
+
class Elapsed
|
361
|
+
def self.inspect
|
362
|
+
"<Middleware::Elapsed>"
|
363
|
+
end
|
364
|
+
|
365
|
+
def initialize(app)
|
366
|
+
@app = app
|
367
|
+
end
|
368
|
+
|
369
|
+
def call(env)
|
370
|
+
with_time_instrumentation do
|
371
|
+
@app.call(env)
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
private
|
376
|
+
|
377
|
+
def with_time_instrumentation
|
378
|
+
starting = now
|
379
|
+
status, headers, body = yield
|
380
|
+
ending = now
|
381
|
+
|
382
|
+
headers["X-Elapsed"] = (ending - starting).round(5).to_s
|
383
|
+
[status, headers, body]
|
384
|
+
end
|
385
|
+
|
386
|
+
def now
|
387
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
388
|
+
end
|
389
|
+
end
|
390
|
+
end
|
391
|
+
end
|
392
|
+
RUBY
|
393
|
+
|
394
|
+
write "lib/test_app/middleware/authentication.rb", <<~RUBY
|
395
|
+
module TestApp
|
396
|
+
module Middleware
|
397
|
+
class Authentication
|
398
|
+
def self.inspect
|
399
|
+
"<Middleware::Auth>"
|
400
|
+
end
|
401
|
+
|
402
|
+
def initialize(app)
|
403
|
+
@app = app
|
404
|
+
end
|
405
|
+
|
406
|
+
def call(env)
|
407
|
+
env["AUTH_USER_ID"] = user_id = "23"
|
408
|
+
status, headers, body = @app.call(env)
|
409
|
+
headers["X-Auth-User-ID"] = user_id
|
410
|
+
|
411
|
+
[status, headers, body]
|
412
|
+
end
|
413
|
+
end
|
414
|
+
end
|
415
|
+
end
|
416
|
+
RUBY
|
417
|
+
|
418
|
+
write "lib/test_app/middleware/rate_limiter.rb", <<~RUBY
|
419
|
+
module TestApp
|
420
|
+
module Middleware
|
421
|
+
class RateLimiter
|
422
|
+
def self.inspect
|
423
|
+
"<Middleware::API::Limiter>"
|
424
|
+
end
|
425
|
+
|
426
|
+
def initialize(app)
|
427
|
+
@app = app
|
428
|
+
end
|
429
|
+
|
430
|
+
def call(env)
|
431
|
+
status, headers, body = @app.call(env)
|
432
|
+
headers["X-API-Rate-Limit-Quota"] = "4000"
|
433
|
+
|
434
|
+
[status, headers, body]
|
435
|
+
end
|
436
|
+
end
|
437
|
+
end
|
438
|
+
end
|
439
|
+
RUBY
|
440
|
+
|
441
|
+
write "lib/test_app/middleware/api_version.rb", <<~RUBY
|
442
|
+
module TestApp
|
443
|
+
module Middleware
|
444
|
+
class ApiVersion
|
445
|
+
def self.inspect
|
446
|
+
"<Middleware::API::Version>"
|
447
|
+
end
|
448
|
+
|
449
|
+
def initialize(app)
|
450
|
+
@app = app
|
451
|
+
end
|
452
|
+
|
453
|
+
def call(env)
|
454
|
+
status, headers, body = @app.call(env)
|
455
|
+
headers["X-API-Version"] = "1"
|
456
|
+
|
457
|
+
[status, headers, body]
|
458
|
+
end
|
459
|
+
end
|
460
|
+
end
|
461
|
+
end
|
462
|
+
RUBY
|
463
|
+
|
464
|
+
write "lib/test_app/middleware/api_deprecation.rb", <<~RUBY
|
465
|
+
module TestApp
|
466
|
+
module Middleware
|
467
|
+
class ApiDeprecation
|
468
|
+
def self.inspect
|
469
|
+
"<Middleware::API::Deprecation>"
|
470
|
+
end
|
471
|
+
|
472
|
+
def initialize(app)
|
473
|
+
@app = app
|
474
|
+
end
|
475
|
+
|
476
|
+
def call(env)
|
477
|
+
status, headers, body = @app.call(env)
|
478
|
+
headers["X-API-Deprecated"] = "API v1 is deprecated"
|
479
|
+
|
480
|
+
[status, headers, body]
|
481
|
+
end
|
482
|
+
end
|
483
|
+
end
|
484
|
+
end
|
485
|
+
RUBY
|
486
|
+
|
487
|
+
write "lib/test_app/middleware/scope_identifier.rb", <<~RUBY
|
488
|
+
module TestApp
|
489
|
+
module Middleware
|
490
|
+
class ScopeIdentifier
|
491
|
+
def self.inspect
|
492
|
+
"<Middleware::API::ScopeIdentifier>"
|
493
|
+
end
|
494
|
+
|
495
|
+
def initialize(app, scope)
|
496
|
+
@app = app
|
497
|
+
@scope = scope
|
498
|
+
end
|
499
|
+
|
500
|
+
def call(env)
|
501
|
+
status, header, body = @app.call(env)
|
502
|
+
header["X-Identifier-" + @scope] = "true"
|
503
|
+
[status, header, body]
|
504
|
+
end
|
505
|
+
|
506
|
+
def inspect
|
507
|
+
"Scope identifier: " + @scope.inspect
|
508
|
+
end
|
509
|
+
end
|
510
|
+
end
|
511
|
+
end
|
512
|
+
RUBY
|
513
|
+
|
514
|
+
write "config/routes.rb", <<~RUBY
|
515
|
+
require "test_app/middleware/elapsed"
|
516
|
+
require "test_app/middleware/authentication"
|
517
|
+
require "test_app/middleware/rate_limiter"
|
518
|
+
require "test_app/middleware/api_version"
|
519
|
+
require "test_app/middleware/api_deprecation"
|
520
|
+
require "test_app/middleware/scope_identifier"
|
521
|
+
|
522
|
+
module TestApp
|
523
|
+
class Routes < Hanami::Routes
|
524
|
+
use TestApp::Middleware::Elapsed
|
525
|
+
use TestApp::Middleware::ScopeIdentifier, "Root"
|
526
|
+
root to: ->(*) { [200, {"Content-Length" => "4"}, ["Home (complex app)"]] }
|
527
|
+
|
528
|
+
mount ->(*) { [200, {"Content-Length" => "7"}, ["Mounted"]] }, at: "/mounted"
|
529
|
+
|
530
|
+
slice :admin, at: "/admin" do
|
531
|
+
use TestApp::Middleware::Authentication
|
532
|
+
use TestApp::Middleware::ScopeIdentifier, "Admin"
|
533
|
+
|
534
|
+
root to: "home.show"
|
535
|
+
end
|
536
|
+
|
537
|
+
# Without leading slash
|
538
|
+
# See: https://github.com/hanami/api/issues/8
|
539
|
+
scope "api" do
|
540
|
+
use TestApp::Middleware::RateLimiter
|
541
|
+
use TestApp::Middleware::ScopeIdentifier, "API"
|
542
|
+
|
543
|
+
root to: ->(*) { [200, {"Content-Length" => "3"}, ["API"]] }
|
544
|
+
|
545
|
+
slice :api_v1, at: "/v1" do
|
546
|
+
use TestApp::Middleware::ApiVersion
|
547
|
+
use TestApp::Middleware::ApiDeprecation
|
548
|
+
use TestApp::Middleware::ScopeIdentifier, "API-V1"
|
549
|
+
|
550
|
+
root to: "home.show"
|
551
|
+
end
|
552
|
+
end
|
553
|
+
end
|
554
|
+
end
|
555
|
+
RUBY
|
556
|
+
|
557
|
+
write "slices/admin/actions/home/show.rb", <<~RUBY
|
558
|
+
module Admin
|
559
|
+
module Actions
|
560
|
+
module Home
|
561
|
+
class Show < Hanami::Action
|
562
|
+
def handle(req, res)
|
563
|
+
res.body = "Hello from admin (User ID " + req.env['AUTH_USER_ID'] + ")"
|
564
|
+
end
|
565
|
+
end
|
566
|
+
end
|
567
|
+
end
|
568
|
+
end
|
569
|
+
RUBY
|
570
|
+
|
571
|
+
write "slices/api_v1/actions/home/show.rb", <<~RUBY
|
572
|
+
module APIV1
|
573
|
+
module Actions
|
574
|
+
module Home
|
575
|
+
class Show < Hanami::Action
|
576
|
+
def handle(req, res)
|
577
|
+
res.body = "API v1"
|
578
|
+
end
|
579
|
+
end
|
580
|
+
end
|
581
|
+
end
|
582
|
+
end
|
583
|
+
RUBY
|
584
|
+
|
585
|
+
require "hanami/boot"
|
586
|
+
end
|
587
|
+
|
588
|
+
it "uses Rack middleware" do
|
589
|
+
get "/"
|
590
|
+
|
591
|
+
expect(last_response.status).to be(200)
|
592
|
+
expect(last_response.body).to eq("Home (complex app)")
|
593
|
+
expect(last_response.headers["X-Identifier-Root"]).to eq("true")
|
594
|
+
expect(last_response.headers).to have_key("X-Elapsed")
|
595
|
+
expect(last_response.headers).to_not have_key("X-Auth-User-ID")
|
596
|
+
expect(last_response.headers).to_not have_key("X-API-Rate-Limit-Quota")
|
597
|
+
expect(last_response.headers).to_not have_key("X-API-Version")
|
598
|
+
end
|
599
|
+
|
600
|
+
it "uses Rack middleware for other paths" do
|
601
|
+
get "/foo"
|
602
|
+
|
603
|
+
expect(last_response.status).to be(404)
|
604
|
+
expect(last_response.headers["X-Identifier-Root"]).to eq("true")
|
605
|
+
expect(last_response.headers).to have_key("X-Elapsed")
|
606
|
+
expect(last_response.headers).to_not have_key("X-Auth-User-ID")
|
607
|
+
expect(last_response.headers).to_not have_key("X-API-Rate-Limit-Quota")
|
608
|
+
expect(last_response.headers).to_not have_key("X-API-Version")
|
609
|
+
end
|
610
|
+
|
611
|
+
context "scoped" do
|
612
|
+
it "uses Rack middleware" do
|
613
|
+
get "/admin"
|
614
|
+
|
615
|
+
expect(last_response.status).to be(200)
|
616
|
+
expect(last_response.headers["X-Identifier-Admin"]).to eq("true")
|
617
|
+
expect(last_response.headers).to have_key("X-Elapsed")
|
618
|
+
expect(last_response.headers).to have_key("X-Auth-User-ID")
|
619
|
+
expect(last_response.headers).to_not have_key("X-API-Rate-Limit-Quota")
|
620
|
+
expect(last_response.headers).to_not have_key("X-API-Version")
|
621
|
+
end
|
622
|
+
|
623
|
+
it "uses Rack middleware for other paths" do
|
624
|
+
get "/admin/users"
|
625
|
+
|
626
|
+
expect(last_response.status).to be(404)
|
627
|
+
expect(last_response.headers["X-Identifier-Admin"]).to eq("true")
|
628
|
+
expect(last_response.headers).to have_key("X-Elapsed")
|
629
|
+
expect(last_response.headers).to have_key("X-Elapsed")
|
630
|
+
expect(last_response.headers).to have_key("X-Auth-User-ID")
|
631
|
+
expect(last_response.headers).to_not have_key("X-API-Rate-Limit-Quota")
|
632
|
+
expect(last_response.headers).to_not have_key("X-API-Version")
|
633
|
+
end
|
634
|
+
|
635
|
+
# See: https://github.com/hanami/api/issues/8
|
636
|
+
it "uses Rack middleware for scope w/o leading slash" do
|
637
|
+
get "/api"
|
638
|
+
|
639
|
+
expect(last_response.status).to be(200)
|
640
|
+
expect(last_response.headers["X-Identifier-Api"]).to eq("true")
|
641
|
+
expect(last_response.headers).to have_key("X-Elapsed")
|
642
|
+
expect(last_response.headers).to_not have_key("X-Auth-User-ID")
|
643
|
+
expect(last_response.headers).to have_key("X-API-Rate-Limit-Quota")
|
644
|
+
expect(last_response.headers).to_not have_key("X-API-Version")
|
645
|
+
end
|
646
|
+
|
647
|
+
# See: https://github.com/hanami/api/issues/8
|
648
|
+
it "uses Rack middleware for nested scope w/o leading slash" do
|
649
|
+
get "/api/v1"
|
650
|
+
|
651
|
+
expect(last_response.status).to be(200)
|
652
|
+
expect(last_response.headers["X-Identifier-API-V1"]).to eq("true")
|
653
|
+
expect(last_response.headers).to have_key("X-Elapsed")
|
654
|
+
expect(last_response.headers).to_not have_key("X-Auth-User-ID")
|
655
|
+
expect(last_response.headers).to have_key("X-API-Rate-Limit-Quota")
|
656
|
+
expect(last_response.headers).to have_key("X-API-Deprecated")
|
657
|
+
expect(last_response.headers["X-API-Version"]).to eq("1")
|
658
|
+
end
|
659
|
+
end
|
660
|
+
end
|
237
661
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "rack/test"
|
4
|
+
require "stringio"
|
4
5
|
|
5
6
|
RSpec.describe "Running a Rack app for a non-booted app", :app_integration do
|
6
7
|
include Rack::Test::Methods
|
@@ -14,7 +15,7 @@ RSpec.describe "Running a Rack app for a non-booted app", :app_integration do
|
|
14
15
|
|
15
16
|
module TestApp
|
16
17
|
class App < Hanami::App
|
17
|
-
config.logger.stream =
|
18
|
+
config.logger.stream = StringIO.new
|
18
19
|
end
|
19
20
|
end
|
20
21
|
RUBY
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "rack/test"
|
4
|
+
require "stringio"
|
4
5
|
|
5
6
|
RSpec.describe "Hanami web app", :app_integration do
|
6
7
|
include Rack::Test::Methods
|
@@ -46,10 +47,25 @@ RSpec.describe "Hanami web app", :app_integration do
|
|
46
47
|
end
|
47
48
|
RUBY
|
48
49
|
|
50
|
+
write "app/actions/users/index.rb", <<~RUBY
|
51
|
+
module TestApp
|
52
|
+
module Actions
|
53
|
+
module Users
|
54
|
+
class Index < Hanami::Action
|
55
|
+
def handle(req, _resp)
|
56
|
+
raise StandardError, "OH NOEZ"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
RUBY
|
63
|
+
|
49
64
|
write "config/routes.rb", <<~RUBY
|
50
65
|
module TestApp
|
51
66
|
class Routes < Hanami::Routes
|
52
67
|
root to: ->(env) { [200, {}, ["OK"]] }
|
68
|
+
get "/users", to: "users.index"
|
53
69
|
end
|
54
70
|
end
|
55
71
|
RUBY
|
@@ -63,6 +79,14 @@ RSpec.describe "Hanami web app", :app_integration do
|
|
63
79
|
logs = -> { Pathname(dir).join("test.log").realpath.read }
|
64
80
|
|
65
81
|
expect(logs.()).to match %r{GET 200 \d+ms 127.0.0.1 /}
|
82
|
+
|
83
|
+
begin
|
84
|
+
get "/users"
|
85
|
+
rescue => e # rubocop:disable Style/RescueStandardError
|
86
|
+
raise unless e.to_s == "OH NOEZ"
|
87
|
+
end
|
88
|
+
|
89
|
+
expect(logs.()).to match %r{OH NOEZ}
|
66
90
|
end
|
67
91
|
end
|
68
92
|
|
@@ -109,7 +133,7 @@ RSpec.describe "Hanami web app", :app_integration do
|
|
109
133
|
|
110
134
|
module TestApp
|
111
135
|
class App < Hanami::App
|
112
|
-
config.logger.stream =
|
136
|
+
config.logger.stream = StringIO.new
|
113
137
|
end
|
114
138
|
end
|
115
139
|
RUBY
|
@@ -214,7 +238,7 @@ RSpec.describe "Hanami web app", :app_integration do
|
|
214
238
|
|
215
239
|
module TestApp
|
216
240
|
class App < Hanami::App
|
217
|
-
config.logger.stream =
|
241
|
+
config.logger.stream = StringIO.new
|
218
242
|
end
|
219
243
|
end
|
220
244
|
RUBY
|
@@ -279,7 +303,7 @@ RSpec.describe "Hanami web app", :app_integration do
|
|
279
303
|
|
280
304
|
module TestApp
|
281
305
|
class App < Hanami::App
|
282
|
-
config.logger.stream =
|
306
|
+
config.logger.stream = StringIO.new
|
283
307
|
end
|
284
308
|
end
|
285
309
|
RUBY
|
@@ -372,8 +396,9 @@ RSpec.describe "Hanami web app", :app_integration do
|
|
372
396
|
require "hanami/boot"
|
373
397
|
|
374
398
|
expect { Hanami.app.rack_app }.to raise_error do |exception|
|
375
|
-
expect(exception).to be_kind_of(Hanami::
|
376
|
-
expect(exception.message).to include("missing.action")
|
399
|
+
expect(exception).to be_kind_of(Hanami::Routes::MissingActionError)
|
400
|
+
expect(exception.message).to include("Could not find action with key \"actions.missing.action\" in TestApp::App")
|
401
|
+
expect(exception.message).to match(%r{define the action class TestApp::Actions::Missing::Action.+actions/missing/action.rb})
|
377
402
|
end
|
378
403
|
end
|
379
404
|
end
|
@@ -403,8 +428,9 @@ RSpec.describe "Hanami web app", :app_integration do
|
|
403
428
|
require "hanami/boot"
|
404
429
|
|
405
430
|
expect { Hanami.app.rack_app }.to raise_error do |exception|
|
406
|
-
expect(exception).to be_kind_of(Hanami::
|
407
|
-
expect(exception.message).to include("missing.action")
|
431
|
+
expect(exception).to be_kind_of(Hanami::Routes::MissingActionError)
|
432
|
+
expect(exception.message).to include("Could not find action with key \"actions.missing.action\" in Admin::Slice")
|
433
|
+
expect(exception.message).to match(%r{define the action class Admin::Actions::Missing::Action.+slices/admin/actions/missing/action.rb})
|
408
434
|
end
|
409
435
|
end
|
410
436
|
end
|
@@ -433,8 +459,9 @@ RSpec.describe "Hanami web app", :app_integration do
|
|
433
459
|
expect { Hanami.app.rack_app }.not_to raise_error
|
434
460
|
|
435
461
|
expect { get "/missing" }.to raise_error do |exception|
|
436
|
-
expect(exception).to be_kind_of(Hanami::
|
437
|
-
expect(exception.message).to include("missing.action")
|
462
|
+
expect(exception).to be_kind_of(Hanami::Routes::MissingActionError)
|
463
|
+
expect(exception.message).to include("Could not find action with key \"actions.missing.action\" in TestApp::App")
|
464
|
+
expect(exception.message).to match(%r{define the action class TestApp::Actions::Missing::Action.+actions/missing/action.rb})
|
438
465
|
end
|
439
466
|
end
|
440
467
|
end
|
@@ -466,8 +493,9 @@ RSpec.describe "Hanami web app", :app_integration do
|
|
466
493
|
expect { Hanami.app.rack_app }.not_to raise_error
|
467
494
|
|
468
495
|
expect { get "/admin/missing" }.to raise_error do |exception|
|
469
|
-
expect(exception).to be_kind_of(Hanami::
|
470
|
-
expect(exception.message).to include("missing.action")
|
496
|
+
expect(exception).to be_kind_of(Hanami::Routes::MissingActionError)
|
497
|
+
expect(exception.message).to include("Could not find action with key \"actions.missing.action\" in Admin::Slice")
|
498
|
+
expect(exception.message).to match(%r{define the action class Admin::Actions::Missing::Action.+slices/admin/actions/missing/action.rb})
|
471
499
|
end
|
472
500
|
end
|
473
501
|
end
|
@@ -63,12 +63,12 @@ RSpec.describe "Hanami setup", :app_integration do
|
|
63
63
|
|
64
64
|
with_tmp_directory(Dir.mktmpdir) do
|
65
65
|
write "config/app.rb", <<~RUBY
|
66
|
-
|
66
|
+
require "hanami"
|
67
67
|
|
68
|
-
|
69
|
-
|
68
|
+
module TestApp
|
69
|
+
class App < Hanami::App
|
70
|
+
end
|
70
71
|
end
|
71
|
-
end
|
72
72
|
RUBY
|
73
73
|
|
74
74
|
expect { setup }.to change { Hanami.app? }.to true
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "rack/test"
|
4
|
+
require "stringio"
|
4
5
|
|
5
6
|
RSpec.describe "Slices / External slices", :app_integration do
|
6
7
|
include Rack::Test::Methods
|
@@ -14,7 +15,7 @@ RSpec.describe "Slices / External slices", :app_integration do
|
|
14
15
|
|
15
16
|
module TestApp
|
16
17
|
class App < Hanami::App
|
17
|
-
config.logger.stream =
|
18
|
+
config.logger.stream = StringIO.new
|
18
19
|
|
19
20
|
require "external/slice"
|
20
21
|
register_slice(:external, External::Slice)
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "stringio"
|
4
|
+
|
3
5
|
RSpec.describe "Slices / Slice configuration", :app_integration do
|
4
6
|
specify "Slices receive a copy of the app configuration, and can make distinct modifications" do
|
5
7
|
with_tmp_directory(Dir.mktmpdir) do
|
@@ -8,7 +10,7 @@ RSpec.describe "Slices / Slice configuration", :app_integration do
|
|
8
10
|
|
9
11
|
module TestApp
|
10
12
|
class App < Hanami::App
|
11
|
-
config.logger.stream =
|
13
|
+
config.logger.stream = StringIO.new
|
12
14
|
|
13
15
|
config.no_auto_register_paths << "structs"
|
14
16
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require "rack/test"
|
4
4
|
|
5
5
|
RSpec.describe "Slices / Slice loading", :app_integration, :aggregate_failures do
|
6
|
-
let(:app_modules) { %i[TestApp Admin
|
6
|
+
let(:app_modules) { %i[TestApp Admin Main] }
|
7
7
|
|
8
8
|
describe "loading specific slices with config.slices" do
|
9
9
|
describe "setup app" do
|
@@ -48,7 +48,7 @@ RSpec.describe "Slices / Slice loading", :app_integration, :aggregate_failures d
|
|
48
48
|
|
49
49
|
expect { Admin::Slice.register_slice :editorial }.not_to(change { Admin::Slice.slices.keys })
|
50
50
|
expect { Admin::Slice.register_slice :shop }.to change { Admin::Slice.slices.keys }.to [:shop]
|
51
|
-
expect(Shop::Slice).to be
|
51
|
+
expect(Admin::Shop::Slice).to be
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
@@ -123,9 +123,9 @@ RSpec.describe "Slices / Slice loading", :app_integration, :aggregate_failures d
|
|
123
123
|
expect(Admin::Slice.slices.keys).to eq [:shop]
|
124
124
|
|
125
125
|
expect(Admin::Slice).to be
|
126
|
-
expect(Shop::Slice).to be
|
126
|
+
expect(Admin::Shop::Slice).to be
|
127
127
|
|
128
|
-
expect { Editorial }.to raise_error(NameError)
|
128
|
+
expect { Admin::Editorial }.to raise_error(NameError)
|
129
129
|
expect { Main }.to raise_error(NameError)
|
130
130
|
end
|
131
131
|
end
|