hanami 2.0.0.alpha8 → 2.0.0.beta1
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 +442 -241
- data/FEATURES.md +30 -9
- data/README.md +1 -3
- data/hanami.gemspec +21 -11
- data/lib/hanami/app.rb +141 -0
- data/lib/hanami/assets/application_configuration.rb +10 -4
- data/lib/hanami/configuration/actions/content_security_policy.rb +5 -5
- data/lib/hanami/configuration/actions/cookies.rb +2 -2
- data/lib/hanami/configuration/actions.rb +10 -4
- data/lib/hanami/configuration/logger.rb +4 -4
- data/lib/hanami/configuration/router.rb +2 -6
- data/lib/hanami/configuration/sessions.rb +1 -1
- data/lib/hanami/configuration/views.rb +9 -4
- data/lib/hanami/configuration.rb +118 -46
- data/lib/hanami/constants.rb +24 -2
- data/lib/hanami/errors.rb +1 -1
- data/lib/hanami/{application → extensions}/action/slice_configured_action.rb +9 -9
- data/lib/hanami/extensions/action.rb +79 -0
- data/lib/hanami/extensions/view/context.rb +106 -0
- data/lib/hanami/{application → extensions}/view/slice_configured_context.rb +10 -10
- data/lib/hanami/{application → extensions}/view/slice_configured_view.rb +12 -6
- data/lib/hanami/extensions/view.rb +33 -0
- data/lib/hanami/extensions.rb +10 -0
- data/lib/hanami/providers/inflector.rb +13 -0
- data/lib/hanami/providers/logger.rb +13 -0
- data/lib/hanami/providers/rack.rb +27 -0
- data/lib/hanami/providers/routes.rb +33 -0
- data/lib/hanami/providers/settings.rb +23 -0
- data/lib/hanami/rake_tasks.rb +61 -0
- data/lib/hanami/routes.rb +51 -0
- data/lib/hanami/server.rb +1 -1
- data/lib/hanami/settings/dotenv_store.rb +58 -0
- data/lib/hanami/settings.rb +90 -0
- data/lib/hanami/setup.rb +4 -2
- data/lib/hanami/{application → slice}/router.rb +18 -13
- data/lib/hanami/slice/routes_helper.rb +37 -0
- data/lib/hanami/{application → slice}/routing/middleware/stack.rb +43 -5
- data/lib/hanami/slice/routing/resolver.rb +97 -0
- data/lib/hanami/{application → slice}/view_name_inferrer.rb +3 -3
- data/lib/hanami/slice.rb +246 -73
- data/lib/hanami/slice_configurable.rb +4 -17
- data/lib/hanami/slice_name.rb +6 -6
- data/lib/hanami/slice_registrar.rb +119 -0
- data/lib/hanami/version.rb +1 -1
- data/lib/hanami/web/rack_logger.rb +1 -1
- data/lib/hanami.rb +34 -26
- data/spec/integration/application_middleware_stack_spec.rb +84 -0
- data/spec/integration/assets/cdn_spec.rb +48 -0
- data/spec/integration/assets/fingerprint_spec.rb +42 -0
- data/spec/integration/assets/helpers_spec.rb +50 -0
- data/spec/integration/assets/serve_spec.rb +70 -0
- data/spec/integration/assets/subresource_integrity_spec.rb +54 -0
- data/spec/integration/body_parsers_spec.rb +50 -0
- data/spec/integration/cli/assets/precompile_spec.rb +147 -0
- data/spec/integration/cli/assets_spec.rb +14 -0
- data/spec/integration/cli/console_spec.rb +105 -0
- data/spec/integration/cli/db/apply_spec.rb +74 -0
- data/spec/integration/cli/db/console_spec.rb +40 -0
- data/spec/integration/cli/db/create_spec.rb +50 -0
- data/spec/integration/cli/db/drop_spec.rb +54 -0
- data/spec/integration/cli/db/migrate_spec.rb +108 -0
- data/spec/integration/cli/db/prepare_spec.rb +36 -0
- data/spec/integration/cli/db/rollback_spec.rb +96 -0
- data/spec/integration/cli/db/version_spec.rb +38 -0
- data/spec/integration/cli/db_spec.rb +21 -0
- data/spec/integration/cli/destroy/action_spec.rb +143 -0
- data/spec/integration/cli/destroy/app_spec.rb +118 -0
- data/spec/integration/cli/destroy/mailer_spec.rb +74 -0
- data/spec/integration/cli/destroy/migration_spec.rb +70 -0
- data/spec/integration/cli/destroy/model_spec.rb +113 -0
- data/spec/integration/cli/destroy_spec.rb +18 -0
- data/spec/integration/cli/generate/action_spec.rb +469 -0
- data/spec/integration/cli/generate/app_spec.rb +215 -0
- data/spec/integration/cli/generate/mailer_spec.rb +189 -0
- data/spec/integration/cli/generate/migration_spec.rb +72 -0
- data/spec/integration/cli/generate/model_spec.rb +290 -0
- data/spec/integration/cli/generate/secret_spec.rb +56 -0
- data/spec/integration/cli/generate_spec.rb +19 -0
- data/spec/integration/cli/new/database_spec.rb +235 -0
- data/spec/integration/cli/new/hanami_head_spec.rb +27 -0
- data/spec/integration/cli/new/template_spec.rb +118 -0
- data/spec/integration/cli/new/test_spec.rb +274 -0
- data/spec/integration/cli/new_spec.rb +970 -0
- data/spec/integration/cli/plugins_spec.rb +39 -0
- data/spec/integration/cli/routes_spec.rb +49 -0
- data/spec/integration/cli/server_spec.rb +626 -0
- data/spec/integration/cli/version_spec.rb +85 -0
- data/spec/integration/early_hints_spec.rb +35 -0
- data/spec/integration/handle_exceptions_spec.rb +244 -0
- data/spec/integration/head_spec.rb +89 -0
- data/spec/integration/http_headers_spec.rb +29 -0
- data/spec/integration/mailer_spec.rb +32 -0
- data/spec/integration/middleware_spec.rb +81 -0
- data/spec/integration/mount_applications_spec.rb +88 -0
- data/spec/integration/project_initializers_spec.rb +40 -0
- data/spec/integration/rackup_spec.rb +35 -0
- data/spec/integration/rake/with_minitest_spec.rb +67 -0
- data/spec/integration/rake/with_rspec_spec.rb +69 -0
- data/spec/integration/routing_helpers_spec.rb +61 -0
- data/spec/integration/security/content_security_policy_spec.rb +46 -0
- data/spec/integration/security/csrf_protection_spec.rb +42 -0
- data/spec/integration/security/force_ssl_spec.rb +29 -0
- data/spec/integration/security/x_content_type_options_spec.rb +46 -0
- data/spec/integration/security/x_frame_options_spec.rb +46 -0
- data/spec/integration/security/x_xss_protection_spec.rb +46 -0
- data/spec/integration/send_file_spec.rb +51 -0
- data/spec/integration/sessions_spec.rb +247 -0
- data/spec/integration/static_middleware_spec.rb +21 -0
- data/spec/integration/streaming_spec.rb +41 -0
- data/spec/integration/unsafe_send_file_spec.rb +52 -0
- data/spec/isolation/hanami/application/already_configured_spec.rb +19 -0
- data/spec/isolation/hanami/application/inherit_anonymous_class_spec.rb +10 -0
- data/spec/isolation/hanami/application/inherit_concrete_class_spec.rb +14 -0
- data/spec/isolation/hanami/application/not_configured_spec.rb +9 -0
- data/spec/isolation/hanami/application/routes/configured_spec.rb +44 -0
- data/spec/isolation/hanami/application/routes/not_configured_spec.rb +16 -0
- data/spec/isolation/hanami/boot/success_spec.rb +50 -0
- data/spec/new_integration/action/configuration_spec.rb +26 -0
- data/spec/new_integration/action/cookies_spec.rb +58 -0
- data/spec/new_integration/action/csrf_protection_spec.rb +54 -0
- data/spec/new_integration/action/routes_spec.rb +73 -0
- data/spec/new_integration/action/sessions_spec.rb +50 -0
- data/spec/new_integration/action/view_integration_spec.rb +165 -0
- data/spec/new_integration/action/view_rendering/automatic_rendering_spec.rb +247 -0
- data/spec/new_integration/action/view_rendering/paired_view_inference_spec.rb +115 -0
- data/spec/new_integration/action/view_rendering_spec.rb +107 -0
- data/spec/new_integration/code_loading/loading_from_app_spec.rb +152 -0
- data/spec/new_integration/code_loading/loading_from_slice_spec.rb +165 -0
- data/spec/new_integration/container/application_routes_helper_spec.rb +48 -0
- data/spec/new_integration/container/auto_injection_spec.rb +53 -0
- data/spec/new_integration/container/auto_registration_spec.rb +86 -0
- data/spec/new_integration/container/autoloader_spec.rb +80 -0
- data/spec/new_integration/container/imports_spec.rb +253 -0
- data/spec/new_integration/container/prepare_container_spec.rb +123 -0
- data/spec/new_integration/container/shutdown_spec.rb +91 -0
- data/spec/new_integration/container/standard_bootable_components_spec.rb +124 -0
- data/spec/new_integration/rack_app/middleware_spec.rb +215 -0
- data/spec/new_integration/rack_app/non_booted_rack_app_spec.rb +105 -0
- data/spec/new_integration/rack_app/rack_app_spec.rb +524 -0
- data/spec/new_integration/settings_spec.rb +115 -0
- data/spec/new_integration/slices/external_slice_spec.rb +92 -0
- data/spec/new_integration/slices/slice_configuration_spec.rb +40 -0
- data/spec/new_integration/slices/slice_routing_spec.rb +226 -0
- data/spec/new_integration/slices/slice_settings_spec.rb +141 -0
- data/spec/new_integration/slices_spec.rb +101 -0
- data/spec/new_integration/view/configuration_spec.rb +49 -0
- data/spec/new_integration/view/context/assets_spec.rb +67 -0
- data/spec/new_integration/view/context/inflector_spec.rb +48 -0
- data/spec/new_integration/view/context/request_spec.rb +61 -0
- data/spec/new_integration/view/context/routes_spec.rb +86 -0
- data/spec/new_integration/view/context/settings_spec.rb +50 -0
- data/spec/new_integration/view/inflector_spec.rb +57 -0
- data/spec/new_integration/view/part_namespace_spec.rb +96 -0
- data/spec/new_integration/view/path_spec.rb +56 -0
- data/spec/new_integration/view/template_spec.rb +68 -0
- data/spec/new_integration/view/views_spec.rb +103 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/support/app_integration.rb +91 -0
- data/spec/support/coverage.rb +1 -0
- data/spec/support/fixtures/hanami-plugin/Gemfile +8 -0
- data/spec/support/fixtures/hanami-plugin/README.md +35 -0
- data/spec/support/fixtures/hanami-plugin/Rakefile +4 -0
- data/spec/support/fixtures/hanami-plugin/bin/console +15 -0
- data/spec/support/fixtures/hanami-plugin/bin/setup +8 -0
- data/spec/support/fixtures/hanami-plugin/hanami-plugin.gemspec +28 -0
- data/spec/support/fixtures/hanami-plugin/lib/hanami/plugin/cli.rb +19 -0
- data/spec/support/fixtures/hanami-plugin/lib/hanami/plugin/version.rb +7 -0
- data/spec/support/fixtures/hanami-plugin/lib/hanami/plugin.rb +8 -0
- data/spec/support/rspec.rb +27 -0
- data/spec/support/shared_examples/cli/generate/app.rb +494 -0
- data/spec/support/shared_examples/cli/generate/migration.rb +32 -0
- data/spec/support/shared_examples/cli/generate/model.rb +81 -0
- data/spec/support/shared_examples/cli/new.rb +97 -0
- data/spec/unit/hanami/configuration/actions/content_security_policy_spec.rb +102 -0
- data/spec/unit/hanami/configuration/actions/cookies_spec.rb +46 -0
- data/spec/unit/hanami/configuration/actions/csrf_protection_spec.rb +57 -0
- data/spec/unit/hanami/configuration/actions/default_values_spec.rb +52 -0
- data/spec/unit/hanami/configuration/actions/sessions_spec.rb +50 -0
- data/spec/unit/hanami/configuration/actions_spec.rb +78 -0
- data/spec/unit/hanami/configuration/base_url_spec.rb +25 -0
- data/spec/unit/hanami/configuration/inflector_spec.rb +35 -0
- data/spec/unit/hanami/configuration/logger_spec.rb +203 -0
- data/spec/unit/hanami/configuration/views_spec.rb +120 -0
- data/spec/unit/hanami/configuration_spec.rb +43 -0
- data/spec/unit/hanami/env_spec.rb +54 -0
- data/spec/unit/hanami/routes_spec.rb +25 -0
- data/spec/unit/hanami/settings/dotenv_store_spec.rb +119 -0
- data/spec/unit/hanami/settings_spec.rb +56 -0
- data/spec/unit/hanami/slice_configurable_spec.rb +104 -0
- data/spec/unit/hanami/slice_name_spec.rb +47 -0
- data/spec/unit/hanami/slice_spec.rb +17 -0
- data/spec/unit/hanami/version_spec.rb +7 -0
- data/spec/unit/hanami/web/rack_logger_spec.rb +78 -0
- metadata +353 -57
- data/lib/hanami/application/action.rb +0 -72
- data/lib/hanami/application/container/providers/inflector.rb +0 -7
- data/lib/hanami/application/container/providers/logger.rb +0 -7
- data/lib/hanami/application/container/providers/rack_logger.rb +0 -15
- data/lib/hanami/application/container/providers/rack_monitor.rb +0 -12
- data/lib/hanami/application/container/providers/routes_helper.rb +0 -9
- data/lib/hanami/application/container/providers/settings.rb +0 -7
- data/lib/hanami/application/routes.rb +0 -55
- data/lib/hanami/application/routes_helper.rb +0 -34
- data/lib/hanami/application/routing/resolver/node.rb +0 -50
- data/lib/hanami/application/routing/resolver/trie.rb +0 -59
- data/lib/hanami/application/routing/resolver.rb +0 -87
- data/lib/hanami/application/routing/router.rb +0 -36
- data/lib/hanami/application/settings/dotenv_store.rb +0 -60
- data/lib/hanami/application/settings.rb +0 -93
- data/lib/hanami/application/slice_registrar.rb +0 -106
- data/lib/hanami/application/view/context.rb +0 -95
- data/lib/hanami/application/view.rb +0 -24
- data/lib/hanami/application.rb +0 -273
- data/lib/hanami/cli/application/cli.rb +0 -40
- data/lib/hanami/cli/application/command.rb +0 -47
- data/lib/hanami/cli/application/commands/console.rb +0 -81
- data/lib/hanami/cli/application/commands.rb +0 -16
- data/lib/hanami/cli/base_command.rb +0 -48
- data/lib/hanami/cli/commands/command.rb +0 -171
- data/lib/hanami/cli/commands/server.rb +0 -88
- data/lib/hanami/cli/commands.rb +0 -65
- data/lib/hanami/configuration/middleware.rb +0 -20
- data/lib/hanami/configuration/source_dirs.rb +0 -42
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe "Sessions", type: :integration do
|
|
4
|
+
it "shows welcome page" do
|
|
5
|
+
with_project do
|
|
6
|
+
server do
|
|
7
|
+
visit "/"
|
|
8
|
+
|
|
9
|
+
expect(page).to have_title("Hanami | The web, with simplicity")
|
|
10
|
+
|
|
11
|
+
expect(page).to have_content("The web, with simplicity.")
|
|
12
|
+
expect(page).to have_content("Hanami is Open Source Software for MVC web development with Ruby.")
|
|
13
|
+
expect(page).to have_content("bundle exec hanami generate action web 'home#index' --url=/")
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "is empty by default" do
|
|
19
|
+
with_project do
|
|
20
|
+
prepare
|
|
21
|
+
|
|
22
|
+
server do
|
|
23
|
+
visit "/"
|
|
24
|
+
|
|
25
|
+
expect(current_path).to eq("/")
|
|
26
|
+
expect(page).to have_content("Sign in")
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "preserves data across requests" do
|
|
32
|
+
with_project do
|
|
33
|
+
prepare
|
|
34
|
+
|
|
35
|
+
server do
|
|
36
|
+
visit "/"
|
|
37
|
+
expect(current_path).to eq("/")
|
|
38
|
+
|
|
39
|
+
click_link("Sign in")
|
|
40
|
+
expect(current_path).to eq("/signin")
|
|
41
|
+
|
|
42
|
+
within "form#signin-form" do
|
|
43
|
+
click_button "Sign in"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
visit "/" # Without this, Capybara losts the session.
|
|
47
|
+
|
|
48
|
+
expect(current_path).to eq("/")
|
|
49
|
+
expect(page).to have_content("Welcome, Luca")
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "clears the session" do
|
|
55
|
+
with_project do
|
|
56
|
+
prepare
|
|
57
|
+
|
|
58
|
+
server do
|
|
59
|
+
given_signedin_user
|
|
60
|
+
|
|
61
|
+
click_link "Sign out"
|
|
62
|
+
|
|
63
|
+
expect(current_path).to eq("/")
|
|
64
|
+
expect(page).to_not have_content("Welcome, Luca")
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
context "when sessions aren't enabled" do
|
|
70
|
+
it "raises error when trying to use `session'" do
|
|
71
|
+
with_project do
|
|
72
|
+
generate "action web home#index --url=/"
|
|
73
|
+
|
|
74
|
+
rewrite "apps/web/controllers/home/index.rb", <<~EOF
|
|
75
|
+
module Web::Controllers::Home
|
|
76
|
+
class Index
|
|
77
|
+
include Web::Action
|
|
78
|
+
|
|
79
|
+
def call(params)
|
|
80
|
+
self.body = session[:foo]
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
EOF
|
|
85
|
+
server do
|
|
86
|
+
visit "/"
|
|
87
|
+
expect(page).to have_content("To use `session', please enable sessions for the current app.")
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "raises error when trying to use `flash'" do
|
|
93
|
+
with_project do
|
|
94
|
+
generate "action web home#index --url=/"
|
|
95
|
+
|
|
96
|
+
rewrite "apps/web/controllers/home/index.rb", <<~EOF
|
|
97
|
+
module Web::Controllers::Home
|
|
98
|
+
class Index
|
|
99
|
+
include Web::Action
|
|
100
|
+
|
|
101
|
+
def call(params)
|
|
102
|
+
self.body = flash[:notice]
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
EOF
|
|
107
|
+
server do
|
|
108
|
+
visit "/"
|
|
109
|
+
expect(page).to have_content("To use `flash', please enable sessions for the current app.")
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
private
|
|
116
|
+
|
|
117
|
+
def prepare
|
|
118
|
+
# Enable sessions
|
|
119
|
+
replace "apps/web/app.rb", "# sessions :cookie, secret: ENV['WEB_SESSIONS_SECRET']", "sessions :cookie, secret: ENV['WEB_SESSIONS_SECRET']"
|
|
120
|
+
|
|
121
|
+
generate_user
|
|
122
|
+
generate_actions
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def generate_user # rubocop:disable Metrics/MethodLength
|
|
126
|
+
generate_model "user"
|
|
127
|
+
generate_migration "create_users", <<~EOF
|
|
128
|
+
Hanami::Model.migration do
|
|
129
|
+
change do
|
|
130
|
+
create_table :users do
|
|
131
|
+
primary_key :id
|
|
132
|
+
column :name, String
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
execute "INSERT INTO users (name) VALUES('Luca')"
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
EOF
|
|
139
|
+
|
|
140
|
+
hanami "db prepare"
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def generate_actions
|
|
144
|
+
generate_home
|
|
145
|
+
generate_signin
|
|
146
|
+
generate_signout
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def generate_home # rubocop:disable Metrics/MethodLength
|
|
150
|
+
generate "action web home#index --url=/"
|
|
151
|
+
replace "apps/web/config/routes.rb", "home#index", 'root to: "home#index"'
|
|
152
|
+
|
|
153
|
+
rewrite "apps/web/controllers/home/index.rb", <<~EOF
|
|
154
|
+
module Web::Controllers::Home
|
|
155
|
+
class Index
|
|
156
|
+
include Web::Action
|
|
157
|
+
expose :current_user
|
|
158
|
+
|
|
159
|
+
def call(params)
|
|
160
|
+
@current_user = UserRepository.new.find(session[:user_id])
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
EOF
|
|
165
|
+
|
|
166
|
+
rewrite "apps/web/templates/home/index.html.erb", <<~EOF
|
|
167
|
+
<h1>Bookshelf</h1>
|
|
168
|
+
|
|
169
|
+
<% if current_user.nil? %>
|
|
170
|
+
<%= link_to "Sign in", "/signin" %>
|
|
171
|
+
<% else %>
|
|
172
|
+
Welcome, <%= current_user.name %>
|
|
173
|
+
<%= link_to "Sign out", "/signout" %>
|
|
174
|
+
<% end %>
|
|
175
|
+
EOF
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def generate_signin
|
|
179
|
+
generate_signin_new_action
|
|
180
|
+
generate_signin_create_action
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def generate_signin_new_action
|
|
184
|
+
generate "action web sessions#new --url=/signin --method=GET"
|
|
185
|
+
rewrite "apps/web/templates/sessions/new.html.erb", <<~EOF
|
|
186
|
+
<h1>Sign in</h1>
|
|
187
|
+
|
|
188
|
+
<%=
|
|
189
|
+
form_for :signin, "/signin", id: "signin-form" do
|
|
190
|
+
div do
|
|
191
|
+
button "Sign in"
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
%>
|
|
195
|
+
EOF
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def generate_signin_create_action
|
|
199
|
+
generate "action web sessions#create --url=/signin --method=POST"
|
|
200
|
+
rewrite "apps/web/controllers/sessions/create.rb", <<~EOF
|
|
201
|
+
module Web::Controllers::Sessions
|
|
202
|
+
class Create
|
|
203
|
+
include Web::Action
|
|
204
|
+
|
|
205
|
+
def call(params)
|
|
206
|
+
session[:user_id] = UserRepository.new.first.id
|
|
207
|
+
redirect_to routes.root_url
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
EOF
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def generate_signout
|
|
215
|
+
generate "action web sessions#destroy --url=/signout --method=GET"
|
|
216
|
+
|
|
217
|
+
rewrite "apps/web/controllers/sessions/destroy.rb", <<~EOF
|
|
218
|
+
module Web::Controllers::Sessions
|
|
219
|
+
class Destroy
|
|
220
|
+
include Web::Action
|
|
221
|
+
|
|
222
|
+
def call(params)
|
|
223
|
+
session[:user_id] = nil
|
|
224
|
+
redirect_to routes.root_url
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
EOF
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def given_signedin_user # rubocop:disable Metrics/AbcSize
|
|
232
|
+
visit "/"
|
|
233
|
+
expect(current_path).to eq("/")
|
|
234
|
+
|
|
235
|
+
click_link("Sign in")
|
|
236
|
+
expect(current_path).to eq("/signin")
|
|
237
|
+
|
|
238
|
+
within "form#signin-form" do
|
|
239
|
+
click_button "Sign in"
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
visit "/" # Without this, Capybara losts the session.
|
|
243
|
+
|
|
244
|
+
expect(current_path).to eq("/")
|
|
245
|
+
expect(page).to have_content("Welcome, Luca")
|
|
246
|
+
end
|
|
247
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe "Static middleware", type: :integration do
|
|
4
|
+
it "serves a public file" do
|
|
5
|
+
with_project do
|
|
6
|
+
write "public/static.txt", "Static file"
|
|
7
|
+
|
|
8
|
+
RSpec::Support::Env["HANAMI_ENV"] = "production"
|
|
9
|
+
RSpec::Support::Env["DATABASE_URL"] = "sqlite://#{Pathname.new('db').join('bookshelf.sqlite')}"
|
|
10
|
+
RSpec::Support::Env["SERVE_STATIC_ASSETS"] = "true"
|
|
11
|
+
RSpec::Support::Env["SMTP_HOST"] = "localhost"
|
|
12
|
+
RSpec::Support::Env["SMTP_PORT"] = "25"
|
|
13
|
+
|
|
14
|
+
server do
|
|
15
|
+
visit "/static.txt"
|
|
16
|
+
|
|
17
|
+
expect(page.body).to include("Static file")
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe "Streaming", type: :integration do
|
|
4
|
+
xit "streams the body" do
|
|
5
|
+
with_project do
|
|
6
|
+
generate "action web home#index --url=/"
|
|
7
|
+
|
|
8
|
+
# Require Rack::Chunked
|
|
9
|
+
unshift "apps/web/app.rb", "require 'rack/chunked'"
|
|
10
|
+
|
|
11
|
+
# Mount middleware
|
|
12
|
+
replace "apps/web/app.rb", "# middleware.use", "middleware.use ::Rack::Chunked"
|
|
13
|
+
replace "apps/web/app.rb", "controller.prepare do", "controller.format text: 'text/plain'\ncontroller.prepare do"
|
|
14
|
+
|
|
15
|
+
rewrite "apps/web/controllers/home/index.rb", <<~EOF
|
|
16
|
+
module Web::Controllers::Home
|
|
17
|
+
class Index
|
|
18
|
+
include Web::Action
|
|
19
|
+
|
|
20
|
+
def call(params)
|
|
21
|
+
self.format = :text
|
|
22
|
+
self.body = Enumerator.new do |y|
|
|
23
|
+
%w(one two three).each { |s| y << s }
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
EOF
|
|
29
|
+
|
|
30
|
+
server do
|
|
31
|
+
get "/", {}, "HTTP_VERSION" => "HTTP/1.1"
|
|
32
|
+
|
|
33
|
+
expect(last_response.headers).to_not have_key("Content-Length")
|
|
34
|
+
expect(last_response.headers["Transfer-Encoding"]).to eq("chunked")
|
|
35
|
+
|
|
36
|
+
expect(last_response.status).to eq(200)
|
|
37
|
+
expect(last_response.body).to eq("3\r\none\r\n3\r\ntwo\r\n5\r\nthree\r\n0\r\n\r\n")
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe "Unsafe send file", type: :integration do
|
|
4
|
+
it "sends file from the public directory" do
|
|
5
|
+
with_project do
|
|
6
|
+
write "public/static.txt", "Static file"
|
|
7
|
+
generate "action web home#index --url=/"
|
|
8
|
+
rewrite "apps/web/controllers/home/index.rb", <<~EOF
|
|
9
|
+
module Web::Controllers::Home
|
|
10
|
+
class Index
|
|
11
|
+
include Web::Action
|
|
12
|
+
|
|
13
|
+
def call(params)
|
|
14
|
+
unsafe_send_file "public/static.txt"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
EOF
|
|
19
|
+
|
|
20
|
+
server do
|
|
21
|
+
get "/"
|
|
22
|
+
|
|
23
|
+
expect(last_response.status).to eq(200)
|
|
24
|
+
expect(last_response.body).to include("Static file")
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "sends file outside of the public directory" do
|
|
30
|
+
with_project do
|
|
31
|
+
generate "action web home#index --url=/"
|
|
32
|
+
rewrite "apps/web/controllers/home/index.rb", <<~EOF
|
|
33
|
+
module Web::Controllers::Home
|
|
34
|
+
class Index
|
|
35
|
+
include Web::Action
|
|
36
|
+
|
|
37
|
+
def call(params)
|
|
38
|
+
unsafe_send_file __FILE__
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
EOF
|
|
43
|
+
|
|
44
|
+
server do
|
|
45
|
+
get "/"
|
|
46
|
+
|
|
47
|
+
expect(last_response.status).to eq(200)
|
|
48
|
+
expect(last_response.body).to include("Web::Controllers::Home")
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bookshelf
|
|
4
|
+
class App < Hanami::App
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
RSpec.describe Hanami do
|
|
9
|
+
describe ".application" do
|
|
10
|
+
it "it raises error when already assigned" do
|
|
11
|
+
expect do
|
|
12
|
+
module Soundcard
|
|
13
|
+
class App < Hanami::App
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end.to raise_error("Hanami.app already configured")
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe Hanami do
|
|
4
|
+
describe ".application" do
|
|
5
|
+
it "it doesn't assign when anonymous class inherits Hanami::Application" do
|
|
6
|
+
Class.new(Hanami::Application)
|
|
7
|
+
expect { Hanami.app }.to raise_error("Hanami.app not configured")
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bookshelf
|
|
4
|
+
class App < Hanami::App
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
RSpec.describe Hanami do
|
|
9
|
+
describe ".application" do
|
|
10
|
+
it "it assign when concrete class inherits Hanami::Application" do
|
|
11
|
+
expect(Hanami.app).to eq(Bookshelf::Application)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "hanami/action"
|
|
4
|
+
|
|
5
|
+
module Bookshelf
|
|
6
|
+
class App < Hanami::App
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
module Web
|
|
11
|
+
end
|
|
12
|
+
Hanami.app.register_slice :web, namespace: Web
|
|
13
|
+
|
|
14
|
+
Hanami.prepare
|
|
15
|
+
|
|
16
|
+
module Web
|
|
17
|
+
class Action < Hanami::Action
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
module Actions
|
|
21
|
+
module Home
|
|
22
|
+
class Index < Web::Action
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
Hanami.app.routes do
|
|
29
|
+
mount :web, at: "/" do
|
|
30
|
+
root to: "home#index"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
RSpec.describe Hanami::Application do
|
|
35
|
+
describe ".routes" do
|
|
36
|
+
subject { Hanami.app.routes }
|
|
37
|
+
|
|
38
|
+
it "returns configured routes" do
|
|
39
|
+
expect(subject).to be_kind_of(Proc)
|
|
40
|
+
# FIXME: make this expectation to pass
|
|
41
|
+
# expect(subject.for(:web).url(:root)).to eq("/")
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bookshelf
|
|
4
|
+
class App < Hanami::App
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
RSpec.describe Hanami::Application do
|
|
9
|
+
describe ".routes" do
|
|
10
|
+
subject { Hanami.app.routes }
|
|
11
|
+
|
|
12
|
+
it "raises error when not configured" do
|
|
13
|
+
expect { subject }.to raise_error("Hanami.app.routes not configured")
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "hanami/action"
|
|
4
|
+
require "hanami/logger"
|
|
5
|
+
|
|
6
|
+
module Bookshelf
|
|
7
|
+
class App < Hanami::App
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module Web
|
|
12
|
+
end
|
|
13
|
+
slice = Hanami.app.register_slice :web, namespace: Web
|
|
14
|
+
|
|
15
|
+
Hanami.prepare
|
|
16
|
+
|
|
17
|
+
Hanami.app.routes do
|
|
18
|
+
mount :web, at: "/" do
|
|
19
|
+
root to: "home#index"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
module Web
|
|
24
|
+
class Action < Hanami::Action
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
module Actions
|
|
28
|
+
module Home
|
|
29
|
+
class Index < Web::Action
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
slice.register "actions.home.index" do
|
|
36
|
+
Web::Actions::Home::Index.new
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
RSpec.describe Hanami do
|
|
40
|
+
describe ".boot" do
|
|
41
|
+
it "assigns Hanami.app, .root, and .logger" do
|
|
42
|
+
pending "Failing due to dry-system changes"
|
|
43
|
+
|
|
44
|
+
Hanami.boot
|
|
45
|
+
expect(Hanami.app.ancestors).to include(Hanami::Application)
|
|
46
|
+
expect(Hanami.app.root).to eq(Dir.pwd)
|
|
47
|
+
expect(Hanami.logger).to be_kind_of(Hanami::Logger)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe "App action / Configuration", :app_integration do
|
|
4
|
+
before do
|
|
5
|
+
module TestApp
|
|
6
|
+
class App < Hanami::App
|
|
7
|
+
config.actions.default_response_format = :json
|
|
8
|
+
register_slice :main
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
Hanami.app.prepare
|
|
13
|
+
|
|
14
|
+
module TestApp
|
|
15
|
+
class Action < Hanami::Action
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
let(:action_class) { TestApp::Action }
|
|
21
|
+
subject(:configuration) { action_class.config }
|
|
22
|
+
|
|
23
|
+
it "applies 'config.actions' configuration from the app" do
|
|
24
|
+
expect(configuration.default_response_format).to eq :json
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe "App action / Cookies", :app_integration do
|
|
4
|
+
before do
|
|
5
|
+
module TestApp
|
|
6
|
+
class App < Hanami::App
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
Hanami.app.instance_eval(&app_hook) if respond_to?(:app_hook)
|
|
11
|
+
Hanami.app.prepare
|
|
12
|
+
|
|
13
|
+
module TestApp
|
|
14
|
+
class Action < Hanami::Action
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
subject(:action_class) { TestApp::Action }
|
|
20
|
+
|
|
21
|
+
context "default configuration" do
|
|
22
|
+
it "has cookie support enabled" do
|
|
23
|
+
expect(action_class.ancestors).to include Hanami::Action::Cookies
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
context "custom cookie options given in app-level config" do
|
|
28
|
+
subject(:app_hook) {
|
|
29
|
+
proc do
|
|
30
|
+
config.actions.cookies = {max_age: 300}
|
|
31
|
+
end
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
it "has cookie support enabled" do
|
|
35
|
+
expect(action_class.ancestors).to include Hanami::Action::Cookies
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "has the cookie options configured" do
|
|
39
|
+
expect(action_class.config.cookies).to eq(max_age: 300)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
context "cookies disabled in app-level config" do
|
|
44
|
+
subject(:app_hook) {
|
|
45
|
+
proc do
|
|
46
|
+
config.actions.cookies = nil
|
|
47
|
+
end
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
it "does not have cookie support enabled" do
|
|
51
|
+
expect(action_class.ancestors.map(&:to_s)).not_to include "Hanami::Action::Cookies"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "has no cookie options configured" do
|
|
55
|
+
expect(action_class.config.cookies).to eq({})
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe "App action / CSRF protection", :app_integration do
|
|
4
|
+
before do
|
|
5
|
+
module TestApp
|
|
6
|
+
class App < Hanami::App
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
Hanami.app.instance_eval(&app_hook) if respond_to?(:app_hook)
|
|
11
|
+
Hanami.app.register_slice :main
|
|
12
|
+
Hanami.app.prepare
|
|
13
|
+
|
|
14
|
+
module TestApp
|
|
15
|
+
class Action < Hanami::Action
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
subject(:action_class) { TestApp::Action }
|
|
21
|
+
|
|
22
|
+
context "app sessions enabled" do
|
|
23
|
+
context "CSRF protection not explicitly configured" do
|
|
24
|
+
let(:app_hook) {
|
|
25
|
+
proc do
|
|
26
|
+
config.actions.sessions = :cookie, {secret: "abc123"}
|
|
27
|
+
end
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
it "has CSRF protection enabled" do
|
|
31
|
+
expect(action_class.ancestors).to include Hanami::Action::CSRFProtection
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
context "CSRF protection explicitly disabled" do
|
|
36
|
+
let(:app_hook) {
|
|
37
|
+
proc do
|
|
38
|
+
config.sessions = :cookie, {secret: "abc123"}
|
|
39
|
+
config.actions.csrf_protection = false
|
|
40
|
+
end
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
it "does not have CSRF protection enabled" do
|
|
44
|
+
expect(action_class.ancestors.map(&:to_s)).not_to include "Hanami::Action::CSRFProtection"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
context "app sessions not enabled" do
|
|
50
|
+
it "does not have CSRF protection enabled" do
|
|
51
|
+
expect(action_class.ancestors.map(&:to_s)).not_to include "Hanami::Action::CSRFProtection"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|