hanami 2.0.0.beta4 → 2.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|