graphql_devise 0.11.4 → 0.13.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.
Files changed (172) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/.travis.yml +7 -0
  4. data/Appraisals +14 -0
  5. data/CHANGELOG.md +56 -0
  6. data/Gemfile +2 -0
  7. data/README.md +219 -20
  8. data/Rakefile +2 -0
  9. data/app/controllers/graphql_devise/application_controller.rb +6 -5
  10. data/app/controllers/graphql_devise/concerns/set_user_by_token.rb +31 -0
  11. data/app/controllers/graphql_devise/graphql_controller.rb +4 -0
  12. data/app/helpers/graphql_devise/application_helper.rb +2 -0
  13. data/app/helpers/graphql_devise/mailer_helper.rb +4 -2
  14. data/app/models/graphql_devise/concerns/model.rb +10 -0
  15. data/app/views/graphql_devise/mailer/confirmation_instructions.html.erb +1 -1
  16. data/app/views/graphql_devise/mailer/reset_password_instructions.html.erb +1 -1
  17. data/config/locales/en.yml +1 -0
  18. data/config/routes.rb +4 -0
  19. data/graphql_devise.gemspec +6 -4
  20. data/lib/generators/graphql_devise/install_generator.rb +30 -5
  21. data/lib/graphql_devise.rb +26 -10
  22. data/lib/graphql_devise/concerns/controller_methods.rb +2 -0
  23. data/lib/graphql_devise/default_operations/mutations.rb +8 -6
  24. data/lib/graphql_devise/default_operations/resolvers.rb +4 -2
  25. data/lib/graphql_devise/engine.rb +2 -0
  26. data/lib/graphql_devise/errors/authentication_error.rb +9 -0
  27. data/lib/graphql_devise/{detailed_user_error.rb → errors/detailed_user_error.rb} +3 -1
  28. data/lib/graphql_devise/errors/error_codes.rb +8 -0
  29. data/lib/graphql_devise/errors/execution_error.rb +6 -0
  30. data/lib/graphql_devise/{user_error.rb → errors/user_error.rb} +3 -1
  31. data/lib/graphql_devise/model/with_email_updater.rb +74 -0
  32. data/lib/graphql_devise/mount_method/operation_preparer.rb +4 -2
  33. data/lib/graphql_devise/mount_method/operation_preparers/custom_operation_preparer.rb +2 -0
  34. data/lib/graphql_devise/mount_method/operation_preparers/default_operation_preparer.rb +8 -2
  35. data/lib/graphql_devise/mount_method/operation_preparers/gql_name_setter.rb +3 -1
  36. data/lib/graphql_devise/mount_method/operation_preparers/mutation_field_setter.rb +5 -2
  37. data/lib/graphql_devise/mount_method/operation_preparers/resolver_type_setter.rb +3 -1
  38. data/lib/graphql_devise/mount_method/operation_preparers/resource_name_setter.rb +4 -2
  39. data/lib/graphql_devise/mount_method/operation_sanitizer.rb +2 -0
  40. data/lib/graphql_devise/mount_method/option_sanitizer.rb +2 -0
  41. data/lib/graphql_devise/mount_method/option_sanitizers/array_checker.rb +2 -0
  42. data/lib/graphql_devise/mount_method/option_sanitizers/class_checker.rb +2 -0
  43. data/lib/graphql_devise/mount_method/option_sanitizers/hash_checker.rb +2 -0
  44. data/lib/graphql_devise/mount_method/option_sanitizers/string_checker.rb +2 -0
  45. data/lib/graphql_devise/mount_method/option_validators/provided_operations_validator.rb +2 -0
  46. data/lib/graphql_devise/mount_method/option_validators/skip_only_validator.rb +2 -0
  47. data/lib/graphql_devise/mount_method/option_validators/supported_operations_validator.rb +2 -0
  48. data/lib/graphql_devise/mount_method/options_validator.rb +2 -0
  49. data/lib/graphql_devise/mount_method/supported_options.rb +2 -0
  50. data/lib/graphql_devise/mutations/base.rb +2 -0
  51. data/lib/graphql_devise/mutations/login.rb +2 -0
  52. data/lib/graphql_devise/mutations/logout.rb +2 -0
  53. data/lib/graphql_devise/mutations/resend_confirmation.rb +5 -5
  54. data/lib/graphql_devise/mutations/send_password_reset.rb +7 -2
  55. data/lib/graphql_devise/mutations/sign_up.rb +5 -6
  56. data/lib/graphql_devise/mutations/update_password.rb +2 -0
  57. data/lib/graphql_devise/rails/routes.rb +7 -72
  58. data/lib/graphql_devise/resolvers/base.rb +2 -0
  59. data/lib/graphql_devise/resolvers/check_password_token.rb +2 -0
  60. data/lib/graphql_devise/resolvers/confirm_account.rb +4 -2
  61. data/lib/graphql_devise/resolvers/dummy.rb +2 -0
  62. data/lib/graphql_devise/resource_loader.rb +89 -0
  63. data/lib/graphql_devise/schema.rb +2 -0
  64. data/lib/graphql_devise/schema_plugin.rb +114 -0
  65. data/lib/graphql_devise/types/authenticatable_type.rb +2 -0
  66. data/lib/graphql_devise/types/credential_type.rb +2 -0
  67. data/lib/graphql_devise/types/mutation_type.rb +2 -0
  68. data/lib/graphql_devise/types/query_type.rb +2 -0
  69. data/lib/graphql_devise/version.rb +3 -1
  70. data/spec/dummy/Rakefile +2 -0
  71. data/spec/dummy/app/controllers/api/v1/graphql_controller.rb +38 -3
  72. data/spec/dummy/app/controllers/application_controller.rb +2 -0
  73. data/spec/dummy/app/graphql/dummy_schema.rb +21 -0
  74. data/spec/dummy/app/graphql/interpreter_schema.rb +11 -0
  75. data/spec/dummy/app/graphql/mutations/login.rb +2 -0
  76. data/spec/dummy/app/graphql/mutations/register_confirmed_user.rb +2 -0
  77. data/spec/dummy/app/graphql/mutations/sign_up.rb +2 -0
  78. data/spec/dummy/app/graphql/mutations/update_user.rb +22 -0
  79. data/spec/dummy/app/graphql/resolvers/public_user.rb +2 -0
  80. data/spec/dummy/app/graphql/resolvers/user_show.rb +2 -0
  81. data/spec/dummy/app/graphql/types/base_object.rb +2 -0
  82. data/spec/dummy/app/graphql/types/custom_admin_type.rb +2 -0
  83. data/spec/dummy/app/graphql/types/mutation_type.rb +4 -1
  84. data/spec/dummy/app/graphql/types/query_type.rb +12 -0
  85. data/spec/dummy/app/graphql/types/user_type.rb +2 -0
  86. data/spec/dummy/app/jobs/application_job.rb +2 -0
  87. data/spec/dummy/app/mailers/application_mailer.rb +2 -0
  88. data/spec/dummy/app/models/admin.rb +2 -0
  89. data/spec/dummy/app/models/application_record.rb +2 -0
  90. data/spec/dummy/app/models/guest.rb +2 -0
  91. data/spec/dummy/app/models/schema_user.rb +13 -0
  92. data/spec/dummy/app/models/user.rb +2 -0
  93. data/spec/dummy/app/models/users.rb +2 -0
  94. data/spec/dummy/app/models/users/customer.rb +2 -0
  95. data/spec/dummy/config.ru +2 -0
  96. data/spec/dummy/config/application.rb +2 -0
  97. data/spec/dummy/config/environment.rb +2 -0
  98. data/spec/dummy/config/environments/development.rb +2 -0
  99. data/spec/dummy/config/environments/production.rb +2 -0
  100. data/spec/dummy/config/environments/test.rb +2 -0
  101. data/spec/dummy/config/initializers/application_controller_renderer.rb +2 -0
  102. data/spec/dummy/config/initializers/backtrace_silencers.rb +2 -0
  103. data/spec/dummy/config/initializers/cors.rb +2 -0
  104. data/spec/dummy/config/initializers/devise_token_auth.rb +2 -0
  105. data/spec/dummy/config/initializers/filter_parameter_logging.rb +2 -0
  106. data/spec/dummy/config/initializers/i18n.rb +2 -0
  107. data/spec/dummy/config/initializers/inflections.rb +2 -0
  108. data/spec/dummy/config/initializers/mime_types.rb +2 -0
  109. data/spec/dummy/config/initializers/wrap_parameters.rb +2 -0
  110. data/spec/dummy/config/puma.rb +2 -0
  111. data/spec/dummy/config/routes.rb +5 -0
  112. data/spec/dummy/config/spring.rb +2 -0
  113. data/spec/dummy/db/migrate/20190815114303_create_users.rb +2 -0
  114. data/spec/dummy/db/migrate/20190824215150_add_auth_available_to_users.rb +2 -0
  115. data/spec/dummy/db/migrate/20190916012505_create_admins.rb +2 -0
  116. data/spec/dummy/db/migrate/20191013213045_create_guests.rb +2 -0
  117. data/spec/dummy/db/migrate/20200321121807_create_users_customers.rb +2 -0
  118. data/spec/dummy/db/migrate/20200621182414_remove_uncofirmed_email_from_admins.rb +7 -0
  119. data/spec/dummy/db/migrate/20200623003142_create_schema_users.rb +46 -0
  120. data/spec/dummy/db/schema.rb +30 -2
  121. data/spec/dummy/db/seeds.rb +2 -0
  122. data/spec/factories/admins.rb +2 -0
  123. data/spec/factories/guests.rb +2 -0
  124. data/spec/factories/schema_users.rb +13 -0
  125. data/spec/factories/users.rb +2 -0
  126. data/spec/factories/users_customers.rb +2 -0
  127. data/spec/generators/graphql_devise/install_generator_spec.rb +23 -0
  128. data/spec/graphql_devise/model/with_email_updater_spec.rb +131 -0
  129. data/spec/graphql_devise_spec.rb +2 -0
  130. data/spec/models/user_spec.rb +2 -0
  131. data/spec/rails_helper.rb +3 -1
  132. data/spec/requests/graphql_controller_spec.rb +82 -0
  133. data/spec/requests/mutations/additional_mutations_spec.rb +2 -0
  134. data/spec/requests/mutations/additional_queries_spec.rb +2 -0
  135. data/spec/requests/mutations/login_spec.rb +2 -0
  136. data/spec/requests/mutations/logout_spec.rb +2 -0
  137. data/spec/requests/mutations/resend_confirmation_spec.rb +46 -29
  138. data/spec/requests/mutations/send_password_reset_spec.rb +42 -12
  139. data/spec/requests/mutations/sign_up_spec.rb +2 -0
  140. data/spec/requests/mutations/update_password_spec.rb +2 -0
  141. data/spec/requests/queries/check_password_token_spec.rb +2 -0
  142. data/spec/requests/queries/confirm_account_spec.rb +9 -1
  143. data/spec/requests/user_controller_spec.rb +237 -23
  144. data/spec/services/mount_method/operation_preparer_spec.rb +10 -3
  145. data/spec/services/mount_method/operation_preparers/custom_operation_preparer_spec.rb +3 -1
  146. data/spec/services/mount_method/operation_preparers/default_operation_preparer_spec.rb +17 -8
  147. data/spec/services/mount_method/operation_preparers/gql_name_setter_spec.rb +2 -0
  148. data/spec/services/mount_method/operation_preparers/mutation_field_setter_spec.rb +20 -4
  149. data/spec/services/mount_method/operation_preparers/resolver_type_setter_spec.rb +2 -0
  150. data/spec/services/mount_method/operation_preparers/resource_name_setter_spec.rb +3 -1
  151. data/spec/services/mount_method/operation_sanitizer_spec.rb +2 -0
  152. data/spec/services/mount_method/option_sanitizer_spec.rb +2 -0
  153. data/spec/services/mount_method/option_sanitizers/array_checker_spec.rb +2 -0
  154. data/spec/services/mount_method/option_sanitizers/class_checker_spec.rb +2 -0
  155. data/spec/services/mount_method/option_sanitizers/hash_checker_spec.rb +2 -0
  156. data/spec/services/mount_method/option_sanitizers/string_checker_spec.rb +2 -0
  157. data/spec/services/mount_method/option_validators/provided_operations_validator_spec.rb +2 -0
  158. data/spec/services/mount_method/option_validators/skip_only_validator_spec.rb +2 -0
  159. data/spec/services/mount_method/option_validators/supported_operations_validator_spec.rb +2 -0
  160. data/spec/services/mount_method/options_validator_spec.rb +2 -0
  161. data/spec/services/resource_loader_spec.rb +84 -0
  162. data/spec/services/schema_plugin_spec.rb +28 -0
  163. data/spec/spec_helper.rb +2 -0
  164. data/spec/support/contexts/graphql_request.rb +2 -0
  165. data/spec/support/factory_bot.rb +2 -0
  166. data/spec/support/matchers/auth_headers_matcher.rb +2 -0
  167. data/spec/support/matchers/not_change_matcher.rb +2 -0
  168. data/spec/support/requests/auth_helpers.rb +2 -0
  169. data/spec/support/requests/json_helpers.rb +2 -0
  170. metadata +120 -87
  171. data/lib/graphql_devise/error_codes.rb +0 -5
  172. data/spec/support/generators/file_helpers.rb +0 -12
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec.describe GraphqlDevise do
2
4
  it 'has a version number' do
3
5
  expect(GraphqlDevise::VERSION).not_to be_nil
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails_helper'
2
4
 
3
5
  RSpec.describe User do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  ENV['RAILS_ENV'] ||= 'test'
@@ -38,9 +40,9 @@ RSpec.configure do |config|
38
40
  config.include(Requests::JsonHelpers, type: :request)
39
41
  config.include(Requests::AuthHelpers, type: :request)
40
42
  config.include(ActiveSupport::Testing::TimeHelpers)
41
- config.include(Generators::FileHelpers, type: :generator)
42
43
 
43
44
  config.before(:suite) do
44
45
  ActionController::Base.allow_forgery_protection = true
45
46
  end
47
+ config.before { ActionMailer::Base.deliveries.clear }
46
48
  end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ RSpec.describe GraphqlDevise::GraphqlController do
6
+ let(:password) { 'password123' }
7
+ let(:user) { create(:user, :confirmed, password: password) }
8
+ let(:params) { { query: query, variables: variables } }
9
+ let(:request_params) do
10
+ if Rails::VERSION::MAJOR >= 5
11
+ { params: params }
12
+ else
13
+ params
14
+ end
15
+ end
16
+
17
+ context 'when variables are a string' do
18
+ let(:variables) { "{\"email\": \"#{user.email}\"}" }
19
+ let(:query) { "mutation($email: String!) { userLogin(email: $email, password: \"#{password}\") { user { email name signInCount } } }" }
20
+
21
+ it 'parses the string variables' do
22
+ post '/api/v1/graphql_auth', request_params
23
+
24
+ expect(json_response).to match(
25
+ data: { userLogin: { user: { email: user.email, name: user.name, signInCount: 1 } } }
26
+ )
27
+ end
28
+
29
+ context 'when variables is an empty string' do
30
+ let(:variables) { '' }
31
+ let(:query) { "mutation { userLogin(email: \"#{user.email}\", password: \"#{password}\") { user { email name signInCount } } }" }
32
+
33
+ it 'returns an empty hash as variables' do
34
+ post '/api/v1/graphql_auth', request_params
35
+
36
+ expect(json_response).to match(
37
+ data: { userLogin: { user: { email: user.email, name: user.name, signInCount: 1 } } }
38
+ )
39
+ end
40
+ end
41
+ end
42
+
43
+ context 'when variables are not a string or hash' do
44
+ let(:variables) { 1 }
45
+ let(:query) { "mutation($email: String!) { userLogin(email: $email, password: \"#{password}\") { user { email name signInCount } } }" }
46
+
47
+ it 'raises an error' do
48
+ expect do
49
+ post '/api/v1/graphql_auth', request_params
50
+ end.to raise_error(ArgumentError)
51
+ end
52
+ end
53
+
54
+ context 'when multiplexing queries' do
55
+ let(:params) do
56
+ {
57
+ _json: [
58
+ { query: "mutation { userLogin(email: \"#{user.email}\", password: \"#{password}\") { user { email name signInCount } } }" },
59
+ { query: "mutation { userLogin(email: \"#{user.email}\", password: \"wrong password\") { user { email name signInCount } } }" }
60
+ ]
61
+ }
62
+ end
63
+
64
+ it 'executes multiple queries in the same request' do
65
+ post '/api/v1/graphql_auth', request_params
66
+
67
+ expect(json_response).to match(
68
+ [
69
+ { data: { userLogin: { user: { email: user.email, name: user.name, signInCount: 1 } } } },
70
+ {
71
+ data: { userLogin: nil },
72
+ errors: [
73
+ hash_including(
74
+ message: 'Invalid login credentials. Please try again.', extensions: { code: 'USER_ERROR' }
75
+ )
76
+ ]
77
+ }
78
+ ]
79
+ )
80
+ end
81
+ end
82
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails_helper'
2
4
 
3
5
  RSpec.describe 'Additional Mutations' do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails_helper'
2
4
 
3
5
  RSpec.describe 'Additional Queries' do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails_helper'
2
4
 
3
5
  RSpec.describe 'Login Requests' do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails_helper'
2
4
 
3
5
  RSpec.describe 'Logout Requests' do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails_helper'
2
4
 
3
5
  RSpec.describe 'Resend confirmation' do
@@ -15,39 +17,58 @@ RSpec.describe 'Resend confirmation' do
15
17
  redirectUrl:"#{redirect}"
16
18
  ) {
17
19
  message
18
- authenticatable {
19
- id
20
- email
21
- }
22
20
  }
23
21
  }
24
22
  GRAPHQL
25
23
  end
26
24
 
27
25
  context 'when params are correct' do
28
- it 'sends an email to the user with confirmation url and returns a success message' do
29
- expect { post_request }.to change(ActionMailer::Base.deliveries, :count).by(1)
30
- expect(json_response[:data][:userResendConfirmation]).to include(
31
- message: 'You will receive an email with instructions for how to confirm your email address in a few minutes.',
32
- authenticatable: {
33
- id: id,
34
- email: email
35
- }
36
- )
26
+ context 'when using the gem schema' do
27
+ it 'sends an email to the user with confirmation url and returns a success message' do
28
+ expect { post_request }.to change(ActionMailer::Base.deliveries, :count).by(1)
29
+ expect(json_response[:data][:userResendConfirmation]).to include(
30
+ message: 'You will receive an email with instructions for how to confirm your email address in a few minutes.'
31
+ )
32
+
33
+ email = Nokogiri::HTML(ActionMailer::Base.deliveries.last.body.encoded)
34
+ link = email.css('a').first
35
+ confirm_link_msg_text = email.css('p')[1].inner_html
36
+ confirm_account_link_text = link.inner_html
37
+
38
+ expect(link['href']).to include('/api/v1/graphql_auth?')
39
+ expect(confirm_link_msg_text).to eq('You can confirm your account email through the link below:')
40
+ expect(confirm_account_link_text).to eq('Confirm my account')
37
41
 
38
- email = Nokogiri::HTML(ActionMailer::Base.deliveries.last.body.encoded)
39
- link = email.css('a').first
40
- confirm_link_msg_text = email.css('p')[1].inner_html
41
- confirm_account_link_text = link.inner_html
42
+ expect do
43
+ get link['href']
44
+ user.reload
45
+ end.to change(user, :confirmed_at).from(NilClass).to(ActiveSupport::TimeWithZone)
46
+ end
47
+ end
48
+
49
+ context 'when using a custom schema' do
50
+ let(:custom_path) { '/api/v1/graphql' }
51
+
52
+ it 'sends an email to the user with confirmation url and returns a success message' do
53
+ expect { post_request(custom_path) }.to change(ActionMailer::Base.deliveries, :count).by(1)
54
+ expect(json_response[:data][:userResendConfirmation]).to include(
55
+ message: 'You will receive an email with instructions for how to confirm your email address in a few minutes.'
56
+ )
42
57
 
43
- expect(confirm_link_msg_text).to eq('You can confirm your account email through the link below:')
44
- expect(confirm_account_link_text).to eq('Confirm my account')
58
+ email = Nokogiri::HTML(ActionMailer::Base.deliveries.last.body.encoded)
59
+ link = email.css('a').first
60
+ confirm_link_msg_text = email.css('p')[1].inner_html
61
+ confirm_account_link_text = link.inner_html
45
62
 
46
- # TODO: Move to feature spec
47
- expect do
48
- get link['href']
49
- user.reload
50
- end.to change(user, :confirmed_at).from(NilClass).to(ActiveSupport::TimeWithZone)
63
+ expect(link['href']).to include("#{custom_path}?")
64
+ expect(confirm_link_msg_text).to eq('You can confirm your account email through the link below:')
65
+ expect(confirm_account_link_text).to eq('Confirm my account')
66
+
67
+ expect do
68
+ get link['href']
69
+ user.reload
70
+ end.to change(user, :confirmed_at).from(NilClass).to(ActiveSupport::TimeWithZone)
71
+ end
51
72
  end
52
73
 
53
74
  context 'when email address uses different casing' do
@@ -56,11 +77,7 @@ RSpec.describe 'Resend confirmation' do
56
77
  it 'honors devise configuration for case insensitive fields' do
57
78
  expect { post_request }.to change(ActionMailer::Base.deliveries, :count).by(1)
58
79
  expect(json_response[:data][:userResendConfirmation]).to include(
59
- message: 'You will receive an email with instructions for how to confirm your email address in a few minutes.',
60
- authenticatable: {
61
- id: id,
62
- email: user.email
63
- }
80
+ message: 'You will receive an email with instructions for how to confirm your email address in a few minutes.'
64
81
  )
65
82
  end
66
83
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails_helper'
2
4
 
3
5
  RSpec.describe 'Send Password Reset Requests' do
@@ -13,26 +15,51 @@ RSpec.describe 'Send Password Reset Requests' do
13
15
  email: "#{email}",
14
16
  redirectUrl: "#{redirect_url}"
15
17
  ) {
16
- authenticatable {
17
- email
18
- }
18
+ message
19
19
  }
20
20
  }
21
21
  GRAPHQL
22
22
  end
23
23
 
24
24
  context 'when params are correct' do
25
- it 'sends password reset email' do
26
- expect { post_request }.to change(ActionMailer::Base.deliveries, :count).by(1)
25
+ context 'when using the gem schema' do
26
+ it 'sends password reset email' do
27
+ expect { post_request }.to change(ActionMailer::Base.deliveries, :count).by(1)
28
+
29
+ expect(json_response[:data][:userSendPasswordReset]).to include(
30
+ message: 'You will receive an email with instructions on how to reset your password in a few minutes.'
31
+ )
32
+
33
+ email = Nokogiri::HTML(ActionMailer::Base.deliveries.last.body.encoded)
34
+ link = email.css('a').first
35
+ expect(link['href']).to include('/api/v1/graphql_auth?')
36
+
37
+ expect do
38
+ get link['href']
39
+ user.reload
40
+ end.to change(user, :allow_password_change).from(false).to(true)
41
+ end
42
+ end
43
+
44
+ context 'when using a custom schema' do
45
+ let(:custom_path) { '/api/v1/graphql' }
46
+
47
+ it 'sends password reset email' do
48
+ expect { post_request(custom_path) }.to change(ActionMailer::Base.deliveries, :count).by(1)
27
49
 
28
- email = Nokogiri::HTML(ActionMailer::Base.deliveries.last.body.encoded)
29
- link = email.css('a').first
50
+ expect(json_response[:data][:userSendPasswordReset]).to include(
51
+ message: 'You will receive an email with instructions on how to reset your password in a few minutes.'
52
+ )
30
53
 
31
- # TODO: Move to feature spec
32
- expect do
33
- get link['href']
34
- user.reload
35
- end.to change(user, :allow_password_change).from(false).to(true)
54
+ email = Nokogiri::HTML(ActionMailer::Base.deliveries.last.body.encoded)
55
+ link = email.css('a').first
56
+ expect(link['href']).to include("#{custom_path}?")
57
+
58
+ expect do
59
+ get link['href']
60
+ user.reload
61
+ end.to change(user, :allow_password_change).from(false).to(true)
62
+ end
36
63
  end
37
64
  end
38
65
 
@@ -41,6 +68,9 @@ RSpec.describe 'Send Password Reset Requests' do
41
68
 
42
69
  it 'honors devise configuration for case insensitive fields' do
43
70
  expect { post_request }.to change(ActionMailer::Base.deliveries, :count).by(1)
71
+ expect(json_response[:data][:userSendPasswordReset]).to include(
72
+ message: 'You will receive an email with instructions on how to reset your password in a few minutes.'
73
+ )
44
74
  end
45
75
  end
46
76
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails_helper'
2
4
 
3
5
  RSpec.describe 'Sign Up process' do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails_helper'
2
4
 
3
5
  RSpec.describe 'Update Password Requests' do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails_helper'
2
4
 
3
5
  RSpec.describe 'Check Password Token Requests' do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails_helper'
2
4
 
3
5
  RSpec.describe 'Account confirmation' do
@@ -22,7 +24,13 @@ RSpec.describe 'Account confirmation' do
22
24
  context 'when confirmation token is correct' do
23
25
  let(:token) { user.confirmation_token }
24
26
 
25
- before { user.send_confirmation_instructions(template_path: ['graphql_devise/mailer']) }
27
+ before do
28
+ user.send_confirmation_instructions(
29
+ template_path: ['graphql_devise/mailer'],
30
+ controller: 'graphql_devise/graphql',
31
+ schema_url: 'http://not-using-this-value.com/gql'
32
+ )
33
+ end
26
34
 
27
35
  it 'confirms the resource and redirects to the sent url' do
28
36
  expect do
@@ -1,39 +1,253 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails_helper'
2
4
 
3
- RSpec.describe 'Integrations with the user controller' do
5
+ RSpec.describe "Integrations with the user's controller" do
4
6
  include_context 'with graphql query request'
5
7
 
6
8
  let(:user) { create(:user, :confirmed) }
7
- let(:query) do
8
- <<-GRAPHQL
9
- query {
10
- user(
11
- id: #{user.id}
12
- ) {
13
- id
14
- email
9
+
10
+ describe 'publicField' do
11
+ let(:query) do
12
+ <<-GRAPHQL
13
+ query {
14
+ publicField
15
15
  }
16
- }
17
- GRAPHQL
16
+ GRAPHQL
17
+ end
18
+
19
+ context 'when using a regular schema' do
20
+ before { post_request('/api/v1/graphql') }
21
+
22
+ it 'does not require authentication' do
23
+ expect(json_response[:data][:publicField]).to eq('Field does not require authentication')
24
+ end
25
+ end
26
+
27
+ context 'when using an interpreter schema' do
28
+ before { post_request('/api/v1/interpreter') }
29
+
30
+ it 'does not require authentication' do
31
+ expect(json_response[:data][:publicField]).to eq('Field does not require authentication')
32
+ end
33
+ end
34
+
35
+ context 'when using the failing route' do
36
+ it 'raises an invalid resource_name error' do
37
+ expect { post_request('/api/v1/failing') }.to raise_error(
38
+ GraphqlDevise::Error,
39
+ 'Invalid resource_name `fail` provided to `graphql_context`. Possible values are: [:user, :admin, :guest, :users_customer, :schema_user].'
40
+ )
41
+ end
42
+ end
18
43
  end
19
44
 
20
- before { post_request('/api/v1/graphql') }
45
+ describe 'privateField' do
46
+ let(:query) do
47
+ <<-GRAPHQL
48
+ query {
49
+ privateField
50
+ }
51
+ GRAPHQL
52
+ end
21
53
 
22
- context 'when user is authenticated' do
23
- let(:headers) { user.create_new_auth_token }
54
+ context 'when using a regular schema' do
55
+ before { post_request('/api/v1/graphql') }
24
56
 
25
- it 'allow to perform the query' do
26
- expect(json_response[:data][:user]).to match(
27
- email: user.email,
28
- id: user.id
29
- )
57
+ context 'when user is authenticated' do
58
+ let(:headers) { user.create_new_auth_token }
59
+
60
+ it 'allows to perform the query' do
61
+ expect(json_response[:data][:privateField]).to eq('Field will always require authentication')
62
+ end
63
+
64
+ context 'when using a SchemaUser' do
65
+ let(:headers) { create(:schema_user, :confirmed).create_new_auth_token }
66
+
67
+ it 'allows to perform the query' do
68
+ expect(json_response[:data][:privateField]).to eq('Field will always require authentication')
69
+ end
70
+ end
71
+ end
72
+
73
+ context 'when user is not authenticated' do
74
+ it 'returns a must sign in error' do
75
+ expect(json_response[:errors]).to contain_exactly(
76
+ hash_including(message: 'privateField field requires authentication', extensions: { code: 'AUTHENTICATION_ERROR' })
77
+ )
78
+ end
79
+ end
80
+ end
81
+
82
+ context 'when using an interpreter schema' do
83
+ before { post_request('/api/v1/interpreter') }
84
+
85
+ context 'when user is authenticated' do
86
+ let(:headers) { user.create_new_auth_token }
87
+
88
+ it 'allows to perform the query' do
89
+ expect(json_response[:data][:privateField]).to eq('Field will always require authentication')
90
+ end
91
+ end
92
+
93
+ context 'when user is not authenticated' do
94
+ it 'returns a must sign in error' do
95
+ expect(json_response[:errors]).to contain_exactly(
96
+ hash_including(message: 'privateField field requires authentication', extensions: { code: 'AUTHENTICATION_ERROR' })
97
+ )
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ describe 'dummyMutation' do
104
+ let(:query) do
105
+ <<-GRAPHQL
106
+ mutation {
107
+ dummyMutation
108
+ }
109
+ GRAPHQL
110
+ end
111
+
112
+ context 'when using a regular schema' do
113
+ before { post_request('/api/v1/graphql') }
114
+
115
+ context 'when user is authenticated' do
116
+ let(:headers) { user.create_new_auth_token }
117
+
118
+ it 'allows to perform the query' do
119
+ expect(json_response[:data][:dummyMutation]).to eq('Necessary so GraphQL gem does not complain about empty mutation type')
120
+ end
121
+ end
122
+
123
+ context 'when user is not authenticated' do
124
+ it 'returns a must sign in error' do
125
+ expect(json_response[:errors]).to contain_exactly(
126
+ hash_including(message: 'dummyMutation field requires authentication', extensions: { code: 'AUTHENTICATION_ERROR' })
127
+ )
128
+ end
129
+ end
130
+ end
131
+
132
+ context 'when using an interpreter schema' do
133
+ before { post_request('/api/v1/interpreter') }
134
+
135
+ context 'when user is authenticated' do
136
+ let(:headers) { user.create_new_auth_token }
137
+
138
+ it 'allows to perform the query' do
139
+ expect(json_response[:data][:dummyMutation]).to eq('Necessary so GraphQL gem does not complain about empty mutation type')
140
+ end
141
+ end
142
+
143
+ context 'when user is not authenticated' do
144
+ it 'returns a must sign in error' do
145
+ expect(json_response[:errors]).to contain_exactly(
146
+ hash_including(message: 'dummyMutation field requires authentication', extensions: { code: 'AUTHENTICATION_ERROR' })
147
+ )
148
+ end
149
+ end
150
+ end
151
+ end
152
+
153
+ describe 'user' do
154
+ let(:query) do
155
+ <<-GRAPHQL
156
+ query {
157
+ user(
158
+ id: #{user.id}
159
+ ) {
160
+ id
161
+ email
162
+ }
163
+ }
164
+ GRAPHQL
165
+ end
166
+
167
+ context 'when using a regular schema' do
168
+ before { post_request('/api/v1/graphql') }
169
+
170
+ context 'when user is authenticated' do
171
+ let(:headers) { user.create_new_auth_token }
172
+
173
+ it 'allows to perform the query' do
174
+ expect(json_response[:data][:user]).to match(
175
+ email: user.email,
176
+ id: user.id
177
+ )
178
+ end
179
+ end
180
+
181
+ context 'when user is not authenticated' do
182
+ it 'returns a must sign in error' do
183
+ expect(json_response[:errors]).to contain_exactly(
184
+ hash_including(message: 'user field requires authentication', extensions: { code: 'AUTHENTICATION_ERROR' })
185
+ )
186
+ end
187
+ end
188
+ end
189
+
190
+ context 'when using an interpreter schema' do
191
+ before { post_request('/api/v1/interpreter') }
192
+
193
+ context 'when user is authenticated' do
194
+ let(:headers) { user.create_new_auth_token }
195
+
196
+ it 'allows to perform the query' do
197
+ expect(json_response[:data][:user]).to match(
198
+ email: user.email,
199
+ id: user.id
200
+ )
201
+ end
202
+ end
203
+
204
+ context 'when user is not authenticated' do
205
+ # Interpreter schema fields are public unless specified otherwise (plugin setting)
206
+ it 'allows to perform the query' do
207
+ expect(json_response[:data][:user]).to match(
208
+ email: user.email,
209
+ id: user.id
210
+ )
211
+ end
212
+ end
30
213
  end
31
214
  end
32
215
 
33
- context 'when user is not authenticated' do
34
- it 'returns a must sign in error' do
35
- expect(json_response[:errors]).to contain_exactly(
36
- 'You need to sign in or sign up before continuing.'
216
+ describe 'updateUser' do
217
+ let(:headers) { user.create_new_auth_token }
218
+ let(:query) do
219
+ <<-GRAPHQL
220
+ mutation {
221
+ updateUser(email: "updated@gmail.com", name: "updated name") {
222
+ user { email name }
223
+ }
224
+ }
225
+ GRAPHQL
226
+ end
227
+
228
+ it 'requires new email confirmation' do
229
+ original_email = user.email
230
+
231
+ expect do
232
+ post_request('/api/v1/graphql?test=value')
233
+ user.reload
234
+ end.to not_change(user, :email).from(original_email).and(
235
+ change(user, :unconfirmed_email).from(nil).to('updated@gmail.com')
236
+ ).and(
237
+ not_change(user, :uid).from(original_email)
238
+ ).and(
239
+ change(user, :name).from(user.name).to('updated name')
240
+ )
241
+
242
+ email = Nokogiri::HTML(ActionMailer::Base.deliveries.last.body.encoded)
243
+ link = email.css('a').first
244
+ expect(link['href']).to include('/api/v1/graphql')
245
+
246
+ expect do
247
+ get link['href']
248
+ user.reload
249
+ end.to change(user, :email).from(original_email).to('updated@gmail.com').and(
250
+ change(user, :uid).from(original_email).to('updated@gmail.com')
37
251
  )
38
252
  end
39
253
  end