rockstart 0.1.0
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +100 -0
- data/Rakefile +19 -0
- data/lib/generators/rockstart/USAGE +13 -0
- data/lib/generators/rockstart/devise/USAGE +9 -0
- data/lib/generators/rockstart/devise/devise_generator.rb +258 -0
- data/lib/generators/rockstart/devise/templates/controllers/passwords_controller.rb +56 -0
- data/lib/generators/rockstart/devise/templates/controllers/registrations_controller.rb +88 -0
- data/lib/generators/rockstart/devise/templates/controllers/sessions_controller.rb +32 -0
- data/lib/generators/rockstart/devise/templates/create_user_migration.rb.tt +11 -0
- data/lib/generators/rockstart/devise/templates/models/user.rb +42 -0
- data/lib/generators/rockstart/devise/templates/spec/factories/users.rb +17 -0
- data/lib/generators/rockstart/devise/templates/spec/models/user_spec.rb +64 -0
- data/lib/generators/rockstart/devise/templates/spec/requests/users/passwords_spec.rb +202 -0
- data/lib/generators/rockstart/devise/templates/spec/requests/users/registrations_spec.rb +445 -0
- data/lib/generators/rockstart/devise/templates/spec/requests/users/sessions_spec.rb +171 -0
- data/lib/generators/rockstart/devise/templates/spec/support/devise_request_spec_helper.rb +29 -0
- data/lib/generators/rockstart/devise/templates/translations.en.yml +4 -0
- data/lib/generators/rockstart/docker/USAGE +10 -0
- data/lib/generators/rockstart/docker/docker_generator.rb +86 -0
- data/lib/generators/rockstart/docker/templates/app/Dockerfile-app +47 -0
- data/lib/generators/rockstart/docker/templates/docker-compose.test.yml +29 -0
- data/lib/generators/rockstart/docker/templates/docker-compose.yml +47 -0
- data/lib/generators/rockstart/docker/templates/dockerignore +16 -0
- data/lib/generators/rockstart/docker/templates/dotenv.docker.tt +4 -0
- data/lib/generators/rockstart/docker/templates/localhost_domains.ext.tt +7 -0
- data/lib/generators/rockstart/docker/templates/setup-localhost.tt +27 -0
- data/lib/generators/rockstart/docker/templates/web/Dockerfile-web +15 -0
- data/lib/generators/rockstart/docker/templates/web/nginx.conf +62 -0
- data/lib/generators/rockstart/frontend_helpers/USAGE +8 -0
- data/lib/generators/rockstart/frontend_helpers/frontend_helpers_generator.rb +65 -0
- data/lib/generators/rockstart/frontend_helpers/templates/application_urls.rb +26 -0
- data/lib/generators/rockstart/frontend_helpers/templates/application_urls_helper.rb +20 -0
- data/lib/generators/rockstart/frontend_helpers/templates/titles.en.yml.tt +5 -0
- data/lib/generators/rockstart/logging/USAGE +8 -0
- data/lib/generators/rockstart/logging/logging_generator.rb +12 -0
- data/lib/generators/rockstart/logging/templates/rockstart/lograge_initializer.rb +50 -0
- data/lib/generators/rockstart/postgres/USAGE +8 -0
- data/lib/generators/rockstart/postgres/postgres_generator.rb +32 -0
- data/lib/generators/rockstart/postgres/templates/config/database.yml.tt +18 -0
- data/lib/generators/rockstart/postgres/templates/migration.rb.tt +7 -0
- data/lib/generators/rockstart/pundit/USAGE +8 -0
- data/lib/generators/rockstart/pundit/pundit_generator.rb +32 -0
- data/lib/generators/rockstart/pundit/templates/app/controllers/concerns/pundit_error_handling.rb +29 -0
- data/lib/generators/rockstart/pundit/templates/app/policies/application_policy.rb +71 -0
- data/lib/generators/rockstart/pundit/templates/app/policies/user_policy.rb +47 -0
- data/lib/generators/rockstart/pundit/templates/config/locales/pundit.en.yml +6 -0
- data/lib/generators/rockstart/pundit/templates/lib/templates/pundit/policy/policy.rb +36 -0
- data/lib/generators/rockstart/pundit/templates/lib/templates/rspec/policy/policy_spec.rb +58 -0
- data/lib/generators/rockstart/pundit/templates/spec/policies/user_policy_spec.rb +95 -0
- data/lib/generators/rockstart/pundit/templates/spec/support/pundit_matchers.rb +7 -0
- data/lib/generators/rockstart/quality/USAGE +10 -0
- data/lib/generators/rockstart/quality/quality_generator.rb +28 -0
- data/lib/generators/rockstart/quality/templates/quality.rake +4 -0
- data/lib/generators/rockstart/quality/templates/rubocop.rake +4 -0
- data/lib/generators/rockstart/quality/templates/rubocop.yml +45 -0
- data/lib/generators/rockstart/rockstart_generator.rb +77 -0
- data/lib/generators/rockstart/rspec/USAGE +8 -0
- data/lib/generators/rockstart/rspec/rspec_generator.rb +70 -0
- data/lib/generators/rockstart/rspec/templates/dotenv.development +1 -0
- data/lib/generators/rockstart/rspec/templates/dotenv.test +1 -0
- data/lib/generators/rockstart/rspec/templates/rspec_templates/model/model_spec.rb +13 -0
- data/lib/generators/rockstart/rspec/templates/support/factory_bot.rb +6 -0
- data/lib/generators/rockstart/rspec/templates/support/shoulda_matchers.rb +9 -0
- data/lib/generators/rockstart/rspec/templates/support/test_helpers.rb +9 -0
- data/lib/generators/rockstart/scaffold_templates/USAGE +8 -0
- data/lib/generators/rockstart/scaffold_templates/scaffold_templates_generator.rb +39 -0
- data/lib/generators/rockstart/scaffold_templates/templates/api_controller.rb.tt +96 -0
- data/lib/generators/rockstart/scaffold_templates/templates/controller.rb.tt +126 -0
- data/lib/generators/rockstart/scaffold_templates/templates/rspec/scaffold/api_request_spec.rb +139 -0
- data/lib/generators/rockstart/scaffold_templates/templates/rspec/scaffold/request_spec.rb +408 -0
- data/lib/generators/rockstart/security/USAGE +13 -0
- data/lib/generators/rockstart/security/security_generator.rb +108 -0
- data/lib/generators/rockstart/security/templates/brakeman.rake +6 -0
- data/lib/generators/rockstart/security/templates/bundler_audit.rake +4 -0
- data/lib/generators/rockstart/security/templates/cache_support.rb +18 -0
- data/lib/generators/rockstart/security/templates/content_security_policy_initializer.rb.tt +56 -0
- data/lib/generators/rockstart/security/templates/content_security_spec.rb.tt +83 -0
- data/lib/generators/rockstart/security/templates/csp_violations_controller.rb +39 -0
- data/lib/generators/rockstart/security/templates/rack_attack.rb +98 -0
- data/lib/generators/rockstart/security/templates/security.rake +9 -0
- data/lib/generators/rockstart/security/templates/session_store_initializer.rb.tt +7 -0
- data/lib/generators/rockstart/smtp_mailer/USAGE +8 -0
- data/lib/generators/rockstart/smtp_mailer/smtp_mailer_generator.rb +30 -0
- data/lib/generators/rockstart/smtp_mailer/templates/config/initializers/action_mailer.rb +10 -0
- data/lib/generators/rockstart/tailwindcss/USAGE +8 -0
- data/lib/generators/rockstart/tailwindcss/tailwindcss_generator.rb +30 -0
- data/lib/generators/rockstart/tailwindcss/templates/application.css +3 -0
- data/lib/generators/rockstart/tailwindcss/templates/postcss.config.js +32 -0
- data/lib/rockstart/base_generator.rb +32 -0
- data/lib/rockstart/env.rb +16 -0
- data/lib/rockstart/railtie.rb +6 -0
- data/lib/rockstart/version.rb +5 -0
- data/lib/rockstart.rb +9 -0
- data/lib/tasks/rockstart_tasks.rake +5 -0
- metadata +187 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe User, type: :model do
|
|
6
|
+
# email:string
|
|
7
|
+
it { is_expected.to have_db_column(:email) }
|
|
8
|
+
# encrypted_password:string
|
|
9
|
+
it { is_expected.to have_db_column(:encrypted_password) }
|
|
10
|
+
# name:string
|
|
11
|
+
it { is_expected.to have_db_column(:name) }
|
|
12
|
+
it { is_expected.not_to validate_presence_of(:name) }
|
|
13
|
+
# admin:boolean
|
|
14
|
+
it { is_expected.to have_db_column(:admin).with_options(default: false) }
|
|
15
|
+
# deleted_at:datetime
|
|
16
|
+
it { is_expected.to have_db_column(:deleted_at).of_type(:datetime) }
|
|
17
|
+
|
|
18
|
+
describe "#given" do
|
|
19
|
+
it "returns the given name from the name" do
|
|
20
|
+
user = User.new(name: "John Smith")
|
|
21
|
+
expect(user.given).to eq "John"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "handles nil name valeus" do
|
|
25
|
+
user = User.new(name: nil)
|
|
26
|
+
expect(user.given).to be_nil
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe "#family" do
|
|
31
|
+
it "returns the family name from the name" do
|
|
32
|
+
user = User.new(name: "John Smith")
|
|
33
|
+
expect(user.family).to eq "Smith"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "handles nil name valeus" do
|
|
37
|
+
user = User.new(name: nil)
|
|
38
|
+
expect(user.family).to be_nil
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe "#to_s" do
|
|
43
|
+
it "returns the persisted name of the user" do
|
|
44
|
+
user = User.new(name: "John Smith")
|
|
45
|
+
user.changes_applied
|
|
46
|
+
expect(user.to_s).to eq "John Smith"
|
|
47
|
+
|
|
48
|
+
user.name = "Jack Smith"
|
|
49
|
+
expect(user.to_s).to eq "John Smith"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "falls back to a generic label when name is not present" do
|
|
53
|
+
user = build_stubbed(:user, name: nil)
|
|
54
|
+
allow(user).to receive(:id?).and_return(true)
|
|
55
|
+
allow(user).to receive(:id).and_return(1234)
|
|
56
|
+
expect(user.to_s).to eq "User #1234"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "returns a generic label when user is not persisted" do
|
|
60
|
+
user = User.new(name: nil)
|
|
61
|
+
expect(user.to_s).to eq "Guest User"
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe "Users::Passwords", type: :request do
|
|
6
|
+
describe "GET /users/password/new" do
|
|
7
|
+
context "as a guest" do
|
|
8
|
+
it "renders a successful response" do
|
|
9
|
+
get new_user_password_path
|
|
10
|
+
expect(response).to be_successful
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe "POST /users/password" do
|
|
16
|
+
context "with a known user email" do
|
|
17
|
+
let(:valid_params) do
|
|
18
|
+
{
|
|
19
|
+
user: {
|
|
20
|
+
email: create(:user).email
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "redirects the user to the login page" do
|
|
26
|
+
post user_password_path, params: valid_params
|
|
27
|
+
expect(response).to redirect_to(new_user_session_path)
|
|
28
|
+
|
|
29
|
+
follow_redirect!
|
|
30
|
+
expect(response.body).to have_selector(".alert-notice", text: t("devise.passwords.send_paranoid_instructions"))
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "sends a password reset email" do
|
|
34
|
+
expect do
|
|
35
|
+
post user_password_path, params: valid_params
|
|
36
|
+
end.to change(ActionMailer::Base.deliveries, :count).by(1)
|
|
37
|
+
|
|
38
|
+
delivery = ActionMailer::Base.deliveries.last
|
|
39
|
+
expect(delivery.to).to eq [valid_params.dig(:user, :email)]
|
|
40
|
+
expect(delivery.subject).to eq t("devise.mailer.reset_password_instructions.subject")
|
|
41
|
+
|
|
42
|
+
# Verify the reset password token is present
|
|
43
|
+
expected_url = edit_user_password_path(reset_password_token: "")
|
|
44
|
+
expect(delivery.body.raw_source).to have_selector("a[href*=\"#{expected_url}\"]")
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
context "with an unknown email address" do
|
|
49
|
+
let(:unknown_user_params) do
|
|
50
|
+
{
|
|
51
|
+
user: {
|
|
52
|
+
email: Faker::Internet.email
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "redirects the user to the login page" do
|
|
58
|
+
post user_password_path, params: unknown_user_params
|
|
59
|
+
expect(response).to redirect_to(url_for_authentication)
|
|
60
|
+
|
|
61
|
+
follow_redirect!
|
|
62
|
+
expect(response.body).to have_selector(".alert-notice", text: t("devise.passwords.send_paranoid_instructions"))
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "does not send any emails" do
|
|
66
|
+
expect do
|
|
67
|
+
post user_password_path, params: unknown_user_params
|
|
68
|
+
end.not_to change(ActionMailer::Base.deliveries, :count)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
describe "GET /users/password/edit" do
|
|
74
|
+
context "with a valid password reset token" do
|
|
75
|
+
let(:valid_reset_password_token) do
|
|
76
|
+
create(:user).send(:set_reset_password_token)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "redirects back to the password reset page without the reset_password_token param" do
|
|
80
|
+
get edit_user_password_path, params: { reset_password_token: valid_reset_password_token }
|
|
81
|
+
expect(response).to redirect_to(edit_user_password_path)
|
|
82
|
+
|
|
83
|
+
follow_redirect!
|
|
84
|
+
expect(response.body).to have_selector("form input[name='user[reset_password_token]'][value='#{valid_reset_password_token}']", visible: false)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
context "with an invalid password reset token" do
|
|
89
|
+
let(:invalid_reset_password_token) do
|
|
90
|
+
Faker::Lorem.words(number: 2).join
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "processes the invalid reset password token the same as a valid token" do
|
|
94
|
+
get edit_user_password_path, params: { reset_password_token: invalid_reset_password_token }
|
|
95
|
+
expect(response).to redirect_to(edit_user_password_path)
|
|
96
|
+
|
|
97
|
+
follow_redirect!
|
|
98
|
+
expect(response.body).to have_selector("form input[name='user[reset_password_token]'][value='#{invalid_reset_password_token}']", visible: false)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
context "with no password request token" do
|
|
103
|
+
it "redirects the user with a warning" do
|
|
104
|
+
get edit_user_password_path
|
|
105
|
+
expect(response).to redirect_to(new_user_session_path)
|
|
106
|
+
|
|
107
|
+
follow_redirect!
|
|
108
|
+
expect(response.body).to have_selector(".alert-alert", text: t("devise.passwords.no_token"))
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
describe "PUT /users/password" do
|
|
114
|
+
context "with valid password change params" do
|
|
115
|
+
let(:user) { create(:user) }
|
|
116
|
+
let(:valid_reset_password_token) do
|
|
117
|
+
user.send(:set_reset_password_token)
|
|
118
|
+
end
|
|
119
|
+
let(:valid_password) do
|
|
120
|
+
Faker::Lorem.words(number: 3).join
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
let(:valid_password_change_params) do
|
|
124
|
+
{
|
|
125
|
+
user: {
|
|
126
|
+
reset_password_token: valid_reset_password_token,
|
|
127
|
+
password: valid_password,
|
|
128
|
+
password_confirmation: valid_password
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
it "redirects the user to the dashboard with a notice" do
|
|
134
|
+
put user_password_path, params: valid_password_change_params
|
|
135
|
+
expect(response).to redirect_to(root_url)
|
|
136
|
+
|
|
137
|
+
follow_redirect!
|
|
138
|
+
expect(response.body).to have_selector(".alert-notice", text: t("devise.passwords.updated"))
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
it "changes the users password" do
|
|
142
|
+
put user_password_path, params: valid_password_change_params
|
|
143
|
+
|
|
144
|
+
user.reload
|
|
145
|
+
expect(user.valid_password?(valid_password)).to be(true)
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
context "with non-matching passwords" do
|
|
150
|
+
let(:user) { create(:user) }
|
|
151
|
+
let(:valid_reset_password_token) do
|
|
152
|
+
user.send(:set_reset_password_token)
|
|
153
|
+
end
|
|
154
|
+
let(:valid_password) do
|
|
155
|
+
Faker::Lorem.words(number: 3).join
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
let(:valid_password_change_params) do
|
|
159
|
+
{
|
|
160
|
+
user: {
|
|
161
|
+
reset_password_token: valid_reset_password_token,
|
|
162
|
+
password: valid_password,
|
|
163
|
+
password_confirmation: valid_password.reverse
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
it "responds with success (displays a form with errors)" do
|
|
169
|
+
put user_password_path, params: valid_password_change_params
|
|
170
|
+
|
|
171
|
+
expect(response).to be_successful
|
|
172
|
+
expect(response.body).to have_selector(".field_with_errors")
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
context "with an invalid password reset token" do
|
|
177
|
+
let(:invalid_reset_password_token) do
|
|
178
|
+
Faker::Lorem.words(number: 2).join
|
|
179
|
+
end
|
|
180
|
+
let(:valid_password) do
|
|
181
|
+
Faker::Lorem.words(number: 3).join
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
let(:invalid_password_change_params) do
|
|
185
|
+
{
|
|
186
|
+
user: {
|
|
187
|
+
reset_password_token: invalid_reset_password_token,
|
|
188
|
+
password: valid_password,
|
|
189
|
+
password_confirmation: valid_password.reverse
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
it "responds with success (displays a form with errors)" do
|
|
195
|
+
put user_password_path, params: invalid_password_change_params
|
|
196
|
+
|
|
197
|
+
expect(response).to be_successful
|
|
198
|
+
expect(response.body).to have_content("Reset password token is invalid")
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe "Users::Registrations", type: :request do
|
|
6
|
+
describe "GET /users/sign_up" do
|
|
7
|
+
context "as a guest" do
|
|
8
|
+
it "renders a successful response" do
|
|
9
|
+
get new_user_registration_path
|
|
10
|
+
expect(response).to be_successful
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
context "as an authenticated user" do
|
|
15
|
+
let(:authenticated_user) { create(:user) }
|
|
16
|
+
|
|
17
|
+
before do
|
|
18
|
+
sign_in(authenticated_user)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "redirects to the dashboard with a warning" do
|
|
22
|
+
get new_user_registration_path
|
|
23
|
+
expect(response).to redirect_to(url_for_user_dashboard)
|
|
24
|
+
|
|
25
|
+
follow_redirect!
|
|
26
|
+
expect(response.body).to have_selector(".alert-alert", text: t("devise.failure.already_authenticated"))
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe "POST /users", :cache_testing do
|
|
32
|
+
context "with valid create user params" do
|
|
33
|
+
let(:valid_password) { Faker::Internet.password }
|
|
34
|
+
let(:valid_registration_params) do
|
|
35
|
+
{
|
|
36
|
+
user: {
|
|
37
|
+
email: Faker::Internet.email,
|
|
38
|
+
password: valid_password,
|
|
39
|
+
password_confirmation: valid_password
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "redirects to the dashboard with a notice" do
|
|
45
|
+
post user_registration_path, params: valid_registration_params
|
|
46
|
+
expect(response).to redirect_to(url_for_user_dashboard)
|
|
47
|
+
|
|
48
|
+
follow_redirect!
|
|
49
|
+
expect(response.body).to have_selector(".alert-notice", text: t("devise.registrations.signed_up"))
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "does not allow authenticated users" do
|
|
53
|
+
sign_in create(:user)
|
|
54
|
+
|
|
55
|
+
post user_registration_path, params: valid_registration_params
|
|
56
|
+
expect(response).to redirect_to(url_for_user_dashboard)
|
|
57
|
+
|
|
58
|
+
follow_redirect!
|
|
59
|
+
expect(response.body).to have_selector(".alert-alert", text: t("devise.failure.already_authenticated"))
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
context "with mismatching passwords" do
|
|
64
|
+
let(:invalid_registration_params) do
|
|
65
|
+
{
|
|
66
|
+
user: {
|
|
67
|
+
email: Faker::Internet.email,
|
|
68
|
+
password: Faker::Internet.password,
|
|
69
|
+
password_confirmation: Faker::Lorem.words(number: 3).join
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it "renders the form with an error" do
|
|
75
|
+
post user_registration_path, params: invalid_registration_params
|
|
76
|
+
expect(response).to be_successful
|
|
77
|
+
|
|
78
|
+
expect(response.body).to have_content("Password confirmation doesn't match Password")
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
context "with an email address matching an existing user" do
|
|
83
|
+
let(:existing_user) { create(:user) }
|
|
84
|
+
let(:valid_password) { Faker::Internet.password }
|
|
85
|
+
let(:existing_registration_params) do
|
|
86
|
+
{
|
|
87
|
+
user: {
|
|
88
|
+
email: existing_user.email,
|
|
89
|
+
password: valid_password,
|
|
90
|
+
password_confirmation: valid_password
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it "renders the form with an error" do
|
|
96
|
+
post user_registration_path, params: existing_registration_params
|
|
97
|
+
expect(response).to be_successful
|
|
98
|
+
|
|
99
|
+
expect(response.body).to have_content("Email has already been taken")
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it "rate limits requests based off ip address" do
|
|
104
|
+
valid_password = Faker::Internet.password
|
|
105
|
+
|
|
106
|
+
5.times do
|
|
107
|
+
post user_registration_path, params: {
|
|
108
|
+
user: {
|
|
109
|
+
email: Faker::Internet.email,
|
|
110
|
+
password: valid_password,
|
|
111
|
+
password_confirmation: valid_password
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
post user_registration_path, params: {
|
|
117
|
+
user: {
|
|
118
|
+
email: Faker::Internet.email,
|
|
119
|
+
password: valid_password,
|
|
120
|
+
password_confirmation: valid_password
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
expect(response).to have_http_status(:too_many_requests)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
describe "GET /users/edit" do
|
|
128
|
+
context "as an authenticated user" do
|
|
129
|
+
let(:authenticated_user) { create(:user) }
|
|
130
|
+
|
|
131
|
+
before do
|
|
132
|
+
sign_in(authenticated_user)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
it "renders the edit user form" do
|
|
136
|
+
get edit_user_registration_path
|
|
137
|
+
expect(response).to be_successful
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
context "as a guest" do
|
|
142
|
+
it "redirects to the new user session path" do
|
|
143
|
+
get edit_user_registration_path
|
|
144
|
+
expect(response).to redirect_to(new_user_session_path)
|
|
145
|
+
|
|
146
|
+
follow_redirect!
|
|
147
|
+
expect(response.body).to have_selector(".alert-alert", text: t("devise.failure.unauthenticated"))
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
describe "PUT /users", :cache_testing do
|
|
153
|
+
context "with update user email params" do
|
|
154
|
+
let(:original_email) { Faker::Internet.email }
|
|
155
|
+
let(:updated_email) { Faker::Internet.email }
|
|
156
|
+
let(:update_user_email_params) do
|
|
157
|
+
{
|
|
158
|
+
user: {
|
|
159
|
+
email: updated_email,
|
|
160
|
+
name: Faker::Name.name
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
context "as an authenticated user" do
|
|
166
|
+
let(:authenticated_user) { create(:user, email: original_email) }
|
|
167
|
+
|
|
168
|
+
before do
|
|
169
|
+
sign_in(authenticated_user)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it "redirects to the dashboard with a notice" do
|
|
173
|
+
put user_registration_path, params: update_user_email_params
|
|
174
|
+
expect(response).to redirect_to(url_for_user_dashboard)
|
|
175
|
+
|
|
176
|
+
follow_redirect!
|
|
177
|
+
expect(response.body).to have_selector(".alert-notice", text: t("devise.registrations.updated"))
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
it "updates the email of the user " do
|
|
181
|
+
put user_registration_path, params: update_user_email_params
|
|
182
|
+
|
|
183
|
+
authenticated_user.reload
|
|
184
|
+
expect(authenticated_user.email).to eq updated_email
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
it "sends an email changed notification to the previous email" do
|
|
188
|
+
expect do
|
|
189
|
+
put user_registration_path, params: update_user_email_params
|
|
190
|
+
end.to change(ActionMailer::Base.deliveries, :count).by(1)
|
|
191
|
+
|
|
192
|
+
delivery = ActionMailer::Base.deliveries.last
|
|
193
|
+
expect(delivery.to).to eq [original_email]
|
|
194
|
+
expect(delivery.subject).to eq t("devise.mailer.email_changed.subject")
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
it "rate limits requests based off ip address" do
|
|
198
|
+
5.times do
|
|
199
|
+
put user_registration_path, params: update_user_email_params
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
put user_registration_path, params: update_user_email_params
|
|
203
|
+
expect(response).to have_http_status(:too_many_requests)
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
context "as a guest" do
|
|
208
|
+
it "redirects to the new user session path" do
|
|
209
|
+
put user_registration_path, params: update_user_email_params
|
|
210
|
+
expect(response).to redirect_to(new_user_session_path)
|
|
211
|
+
|
|
212
|
+
follow_redirect!
|
|
213
|
+
expect(response.body).to have_selector(".alert-alert", text: t("devise.failure.unauthenticated"))
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
context "with update password params" do
|
|
219
|
+
let(:current_password) { Faker::Internet.password }
|
|
220
|
+
let(:updated_password) { Faker::Internet.password }
|
|
221
|
+
let(:update_user_password_params) do
|
|
222
|
+
{
|
|
223
|
+
user: {
|
|
224
|
+
current_password: current_password,
|
|
225
|
+
password: updated_password,
|
|
226
|
+
password_confirmation: updated_password
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
context "as an authenticated user" do
|
|
232
|
+
let(:authenticated_user) { create(:user, password: current_password) }
|
|
233
|
+
|
|
234
|
+
before do
|
|
235
|
+
sign_in(authenticated_user)
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
it "redirects to the dashboard with a notice" do
|
|
239
|
+
put user_registration_path, params: update_user_password_params
|
|
240
|
+
expect(response).to redirect_to(url_for_user_dashboard)
|
|
241
|
+
|
|
242
|
+
follow_redirect!
|
|
243
|
+
expect(response.body).to have_selector(".alert-notice", text: t("devise.registrations.updated"))
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
it "updates the password of the user" do
|
|
247
|
+
put user_registration_path, params: update_user_password_params
|
|
248
|
+
|
|
249
|
+
authenticated_user.reload
|
|
250
|
+
expect(authenticated_user.valid_password?(updated_password)).to be(true)
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
it "sends a password changed notification to the previous email" do
|
|
254
|
+
expect do
|
|
255
|
+
put user_registration_path, params: update_user_password_params
|
|
256
|
+
end.to change(ActionMailer::Base.deliveries, :count).by(1)
|
|
257
|
+
|
|
258
|
+
delivery = ActionMailer::Base.deliveries.last
|
|
259
|
+
expect(delivery.to).to eq [authenticated_user.email]
|
|
260
|
+
expect(delivery.subject).to eq t("devise.mailer.password_change.subject")
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
context "with incorrect current password password params" do
|
|
266
|
+
let(:updated_password) { Faker::Internet.password }
|
|
267
|
+
let(:invalid_current_password_params) do
|
|
268
|
+
{
|
|
269
|
+
user: {
|
|
270
|
+
current_password: Faker::Internet.password,
|
|
271
|
+
password: updated_password,
|
|
272
|
+
password_confirmation: updated_password
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
context "as an authenticated user" do
|
|
278
|
+
let(:authenticated_user) { create(:user) }
|
|
279
|
+
|
|
280
|
+
before do
|
|
281
|
+
sign_in(authenticated_user)
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
it "renders the form with an error" do
|
|
285
|
+
put user_registration_path, params: invalid_current_password_params
|
|
286
|
+
expect(response).to be_successful
|
|
287
|
+
|
|
288
|
+
expect(response.body).to have_content("Current password is invalid")
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
context "with incorrect password confirmation params" do
|
|
294
|
+
let(:current_password) { Faker::Internet.password }
|
|
295
|
+
let(:invalid_password_confirmation_params) do
|
|
296
|
+
{
|
|
297
|
+
user: {
|
|
298
|
+
current_password: current_password,
|
|
299
|
+
password: Faker::Internet.password,
|
|
300
|
+
password_confirmation: Faker::Internet.password
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
context "as an authenticated user" do
|
|
306
|
+
let(:authenticated_user) { create(:user, password: current_password) }
|
|
307
|
+
|
|
308
|
+
before do
|
|
309
|
+
sign_in(authenticated_user)
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
it "renders the form with an error" do
|
|
313
|
+
put user_registration_path, params: invalid_password_confirmation_params
|
|
314
|
+
expect(response).to be_successful
|
|
315
|
+
|
|
316
|
+
expect(response.body).to have_content("Password confirmation doesn't match Password")
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
context "with no password confirmation param" do
|
|
322
|
+
let(:current_password) { Faker::Internet.password }
|
|
323
|
+
let(:no_password_confirmation_params) do
|
|
324
|
+
{
|
|
325
|
+
user: {
|
|
326
|
+
current_password: current_password,
|
|
327
|
+
password: Faker::Internet.password
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
context "as an authenticated user" do
|
|
333
|
+
let(:authenticated_user) { create(:user, password: current_password) }
|
|
334
|
+
|
|
335
|
+
before do
|
|
336
|
+
sign_in(authenticated_user)
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
it "renders the form with an error" do
|
|
340
|
+
put user_registration_path, params: no_password_confirmation_params
|
|
341
|
+
expect(response).to be_successful
|
|
342
|
+
|
|
343
|
+
expect(response.body).to have_content("Password confirmation doesn't match Password")
|
|
344
|
+
end
|
|
345
|
+
end
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
context "with update user details params" do
|
|
349
|
+
let(:existing_email) { Faker::Internet.email }
|
|
350
|
+
let(:updated_name) { Faker::Name.name }
|
|
351
|
+
let(:update_user_details_params) do
|
|
352
|
+
{
|
|
353
|
+
user: {
|
|
354
|
+
email: existing_email,
|
|
355
|
+
name: updated_name
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
context "as an authenticated user" do
|
|
361
|
+
let(:authenticated_user) { create(:user, email: existing_email) }
|
|
362
|
+
|
|
363
|
+
before do
|
|
364
|
+
sign_in(authenticated_user)
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
it "redirects to the dashboard with a notice" do
|
|
368
|
+
put user_registration_path, params: update_user_details_params
|
|
369
|
+
expect(response).to redirect_to(url_for_user_dashboard)
|
|
370
|
+
|
|
371
|
+
follow_redirect!
|
|
372
|
+
expect(response.body).to have_selector(".alert-notice", text: t("devise.registrations.updated"))
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
it "updates the personal details of the user " do
|
|
376
|
+
put user_registration_path, params: update_user_details_params
|
|
377
|
+
|
|
378
|
+
authenticated_user.reload
|
|
379
|
+
expect(authenticated_user.email).to eq existing_email
|
|
380
|
+
expect(authenticated_user.name).to eq updated_name
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
it "does not send any emails" do
|
|
384
|
+
expect do
|
|
385
|
+
put user_registration_path, params: update_user_details_params
|
|
386
|
+
end.not_to change(ActionMailer::Base.deliveries, :count)
|
|
387
|
+
end
|
|
388
|
+
end
|
|
389
|
+
end
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
describe "DELETE /users" do
|
|
393
|
+
context "with an authenticated user" do
|
|
394
|
+
let(:authenticated_user) { create(:user) }
|
|
395
|
+
|
|
396
|
+
before do
|
|
397
|
+
sign_in(authenticated_user)
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
it "redirects to the registration page with a notice" do
|
|
401
|
+
delete user_registration_path
|
|
402
|
+
expect(response).to redirect_to(new_user_registration_path)
|
|
403
|
+
|
|
404
|
+
follow_redirect!
|
|
405
|
+
expect(response.body).to have_selector(".alert-notice", text: t("devise.registrations.destroyed"))
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
it "soft deletes the User" do
|
|
409
|
+
expect do
|
|
410
|
+
delete user_registration_path
|
|
411
|
+
end.not_to change(User, :count)
|
|
412
|
+
|
|
413
|
+
authenticated_user.reload
|
|
414
|
+
expect(authenticated_user).to be_deleted_at
|
|
415
|
+
expect(authenticated_user).not_to be_active_for_authentication
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
context "with an authenticated admin" do
|
|
421
|
+
let(:authenticated_admin) { create(:user, :admin) }
|
|
422
|
+
|
|
423
|
+
before do
|
|
424
|
+
sign_in(authenticated_admin)
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
it "redirects to the dashboard page with an error" do
|
|
428
|
+
delete user_registration_path
|
|
429
|
+
expect(response).to redirect_to(url_for_user_dashboard)
|
|
430
|
+
|
|
431
|
+
follow_redirect!
|
|
432
|
+
expect(response.body).to have_selector(".alert-error", text: t("pundit.user_policy.destroy?", default: t("pundit.default")))
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
it "does not soft delete the user" do
|
|
436
|
+
expect do
|
|
437
|
+
delete user_registration_path
|
|
438
|
+
end.not_to change(User, :count)
|
|
439
|
+
|
|
440
|
+
authenticated_admin.reload
|
|
441
|
+
expect(authenticated_admin).to be_active_for_authentication
|
|
442
|
+
expect(authenticated_admin).not_to be_deleted_at
|
|
443
|
+
end
|
|
444
|
+
end
|
|
445
|
+
end
|