graphql_devise 0.14.0 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +118 -0
  3. data/Appraisals +39 -5
  4. data/CHANGELOG.md +68 -6
  5. data/README.md +150 -51
  6. data/Rakefile +2 -1
  7. data/app/controllers/graphql_devise/concerns/additional_controller_methods.rb +72 -0
  8. data/app/controllers/graphql_devise/concerns/set_user_by_token.rb +5 -27
  9. data/app/controllers/graphql_devise/graphql_controller.rb +1 -1
  10. data/app/helpers/graphql_devise/mailer_helper.rb +2 -2
  11. data/app/models/graphql_devise/concerns/additional_model_methods.rb +21 -0
  12. data/app/models/graphql_devise/concerns/model.rb +6 -9
  13. data/docs/usage/reset_password_flow.md +90 -0
  14. data/graphql_devise.gemspec +2 -2
  15. data/lib/generators/graphql_devise/install_generator.rb +1 -1
  16. data/lib/graphql_devise.rb +20 -6
  17. data/lib/graphql_devise/concerns/controller_methods.rb +3 -3
  18. data/lib/graphql_devise/mount_method/operation_preparer.rb +6 -6
  19. data/lib/graphql_devise/mount_method/operation_preparers/custom_operation_preparer.rb +6 -4
  20. data/lib/graphql_devise/mount_method/operation_preparers/default_operation_preparer.rb +6 -4
  21. data/lib/graphql_devise/mount_method/operation_preparers/{resource_name_setter.rb → resource_klass_setter.rb} +4 -4
  22. data/lib/graphql_devise/resolvers/confirm_account.rb +1 -1
  23. data/lib/graphql_devise/resource_loader.rb +26 -11
  24. data/lib/graphql_devise/schema_plugin.rb +41 -18
  25. data/lib/graphql_devise/version.rb +1 -1
  26. data/spec/dummy/app/controllers/api/v1/graphql_controller.rb +13 -2
  27. data/spec/dummy/app/graphql/dummy_schema.rb +4 -3
  28. data/spec/dummy/app/graphql/types/query_type.rb +5 -0
  29. data/spec/dummy/config/routes.rb +2 -1
  30. data/spec/dummy/db/migrate/20200623003142_create_schema_users.rb +0 -1
  31. data/spec/dummy/db/migrate/20210516211417_add_vip_to_users.rb +5 -0
  32. data/spec/dummy/db/schema.rb +4 -4
  33. data/spec/generators/graphql_devise/install_generator_spec.rb +1 -1
  34. data/spec/graphql/user_queries_spec.rb +120 -0
  35. data/spec/requests/graphql_controller_spec.rb +12 -11
  36. data/spec/requests/queries/introspection_query_spec.rb +149 -0
  37. data/spec/requests/user_controller_spec.rb +93 -32
  38. data/spec/services/mount_method/operation_preparer_spec.rb +5 -5
  39. data/spec/services/mount_method/operation_preparers/custom_operation_preparer_spec.rb +5 -5
  40. data/spec/services/mount_method/operation_preparers/default_operation_preparer_spec.rb +5 -5
  41. data/spec/services/mount_method/operation_preparers/{resource_name_setter_spec.rb → resource_klass_setter_spec.rb} +6 -6
  42. data/spec/services/resource_loader_spec.rb +5 -5
  43. data/spec/support/contexts/graphql_request.rb +11 -3
  44. data/spec/support/contexts/schema_test.rb +14 -0
  45. metadata +25 -14
  46. data/.travis.yml +0 -79
@@ -4,23 +4,25 @@ module GraphqlDevise
4
4
  module MountMethod
5
5
  module OperationPreparers
6
6
  class DefaultOperationPreparer
7
- def initialize(selected_operations:, custom_keys:, mapping_name:, preparer:)
7
+ def initialize(selected_operations:, custom_keys:, model:, preparer:)
8
8
  @selected_operations = selected_operations
9
9
  @custom_keys = custom_keys
10
- @mapping_name = mapping_name
10
+ @model = model
11
11
  @preparer = preparer
12
12
  end
13
13
 
14
14
  def call
15
+ mapping_name = GraphqlDevise.to_mapping_name(@model)
16
+
15
17
  @selected_operations.except(*@custom_keys).each_with_object({}) do |(action, operation_info), result|
16
- mapped_action = "#{@mapping_name}_#{action}"
18
+ mapped_action = "#{mapping_name}_#{action}"
17
19
  operation = operation_info[:klass]
18
20
  options = operation_info.except(:klass)
19
21
 
20
22
  result[mapped_action.to_sym] = [
21
23
  OperationPreparers::GqlNameSetter.new(mapped_action),
22
24
  @preparer,
23
- OperationPreparers::ResourceNameSetter.new(@mapping_name)
25
+ OperationPreparers::ResourceKlassSetter.new(@model)
24
26
  ].reduce(child_class(operation)) do |prepared_operation, preparer|
25
27
  preparer.call(prepared_operation, **options)
26
28
  end
@@ -3,13 +3,13 @@
3
3
  module GraphqlDevise
4
4
  module MountMethod
5
5
  module OperationPreparers
6
- class ResourceNameSetter
7
- def initialize(name)
8
- @name = name
6
+ class ResourceKlassSetter
7
+ def initialize(klass)
8
+ @klass = klass
9
9
  end
10
10
 
11
11
  def call(operation, **)
12
- operation.instance_variable_set(:@resource_name, @name)
12
+ operation.instance_variable_set(:@resource_klass, @klass)
13
13
 
14
14
  operation
15
15
  end
@@ -32,7 +32,7 @@ module GraphqlDevise
32
32
  end
33
33
 
34
34
  controller.redirect_to(redirect_to_link)
35
- { authenticatable: resource }
35
+ resource
36
36
  else
37
37
  raise_user_error(I18n.t('graphql_devise.confirmations.invalid_token'))
38
38
  end
@@ -10,12 +10,27 @@ module GraphqlDevise
10
10
  end
11
11
 
12
12
  def call(query, mutation)
13
- mapping_name = @resource.to_s.underscore.tr('/', '_').to_sym
14
-
15
13
  # clean_options responds to all keys defined in GraphqlDevise::MountMethod::SUPPORTED_OPTIONS
16
14
  clean_options = GraphqlDevise::MountMethod::OptionSanitizer.new(@options).call!
17
15
 
18
- return clean_options if GraphqlDevise.resource_mounted?(mapping_name) && @routing
16
+ model = if @resource.is_a?(String)
17
+ ActiveSupport::Deprecation.warn(<<-DEPRECATION.strip_heredoc, caller)
18
+ Providing a String as the model you want to mount is deprecated and will be removed in a future version of
19
+ this gem. Please use the actual model constant instead.
20
+
21
+ EXAMPLE
22
+
23
+ GraphqlDevise::ResourceLoader.new(User) # instead of GraphqlDevise::ResourceLoader.new('User')
24
+
25
+ mount_graphql_devise_for User # instead of mount_graphql_devise_for 'User'
26
+ DEPRECATION
27
+ @resource.constantize
28
+ else
29
+ @resource
30
+ end
31
+
32
+ # Necesary when mounting a resource via route file as Devise forces the reloading of routes
33
+ return clean_options if GraphqlDevise.resource_mounted?(model) && @routing
19
34
 
20
35
  validate_options!(clean_options)
21
36
 
@@ -23,7 +38,7 @@ module GraphqlDevise
23
38
  "Types::#{@resource}Type".safe_constantize ||
24
39
  GraphqlDevise::Types::AuthenticatableType
25
40
 
26
- prepared_mutations = prepare_mutations(mapping_name, clean_options, authenticatable_type)
41
+ prepared_mutations = prepare_mutations(model, clean_options, authenticatable_type)
27
42
 
28
43
  if prepared_mutations.any? && mutation.blank?
29
44
  raise GraphqlDevise::Error, 'You need to provide a mutation type unless all mutations are skipped'
@@ -33,7 +48,7 @@ module GraphqlDevise
33
48
  mutation.field(action, mutation: prepared_mutation, authenticate: false)
34
49
  end
35
50
 
36
- prepared_resolvers = prepare_resolvers(mapping_name, clean_options, authenticatable_type)
51
+ prepared_resolvers = prepare_resolvers(model, clean_options, authenticatable_type)
37
52
 
38
53
  if prepared_resolvers.any? && query.blank?
39
54
  raise GraphqlDevise::Error, 'You need to provide a query type unless all queries are skipped'
@@ -43,17 +58,17 @@ module GraphqlDevise
43
58
  query.field(action, resolver: resolver, authenticate: false)
44
59
  end
45
60
 
46
- GraphqlDevise.add_mapping(mapping_name, @resource)
47
- GraphqlDevise.mount_resource(mapping_name) if @routing
61
+ GraphqlDevise.add_mapping(GraphqlDevise.to_mapping_name(@resource).to_sym, @resource)
62
+ GraphqlDevise.mount_resource(model) if @routing
48
63
 
49
64
  clean_options
50
65
  end
51
66
 
52
67
  private
53
68
 
54
- def prepare_resolvers(mapping_name, clean_options, authenticatable_type)
69
+ def prepare_resolvers(model, clean_options, authenticatable_type)
55
70
  GraphqlDevise::MountMethod::OperationPreparer.new(
56
- mapping_name: mapping_name,
71
+ model: model,
57
72
  custom: clean_options.operations,
58
73
  additional_operations: clean_options.additional_queries,
59
74
  preparer: GraphqlDevise::MountMethod::OperationPreparers::ResolverTypeSetter.new(authenticatable_type),
@@ -63,9 +78,9 @@ module GraphqlDevise
63
78
  ).call
64
79
  end
65
80
 
66
- def prepare_mutations(mapping_name, clean_options, authenticatable_type)
81
+ def prepare_mutations(model, clean_options, authenticatable_type)
67
82
  GraphqlDevise::MountMethod::OperationPreparer.new(
68
- mapping_name: mapping_name,
83
+ model: model,
69
84
  custom: clean_options.operations,
70
85
  additional_operations: clean_options.additional_mutations,
71
86
  preparer: GraphqlDevise::MountMethod::OperationPreparers::MutationFieldSetter.new(authenticatable_type),
@@ -2,18 +2,20 @@
2
2
 
3
3
  module GraphqlDevise
4
4
  class SchemaPlugin
5
+ # NOTE: Based on GQL-Ruby docs https://graphql-ruby.org/schema/introspection.html
6
+ INTROSPECTION_FIELDS = ['__schema', '__type', '__typename']
5
7
  DEFAULT_NOT_AUTHENTICATED = ->(field) { raise GraphqlDevise::AuthenticationError, "#{field} field requires authentication" }
6
8
 
7
- def initialize(query: nil, mutation: nil, authenticate_default: true, resource_loaders: [], unauthenticated_proc: DEFAULT_NOT_AUTHENTICATED)
9
+ def initialize(query: nil, mutation: nil, authenticate_default: true, public_introspection: !Rails.env.production?, resource_loaders: [], unauthenticated_proc: DEFAULT_NOT_AUTHENTICATED)
8
10
  @query = query
9
11
  @mutation = mutation
10
12
  @resource_loaders = resource_loaders
11
13
  @authenticate_default = authenticate_default
14
+ @public_introspection = public_introspection
12
15
  @unauthenticated_proc = unauthenticated_proc
13
16
 
14
17
  # Must happen on initialize so operations are loaded before the types are added to the schema on GQL < 1.10
15
18
  load_fields
16
- reconfigure_warden!
17
19
  end
18
20
 
19
21
  def use(schema_definition)
@@ -24,14 +26,27 @@ module GraphqlDevise
24
26
  # Authenticate only root level queries
25
27
  return yield unless event == 'execute_field' && path(trace_data).count == 1
26
28
 
27
- field = traced_field(trace_data)
28
- provided_value = authenticate_option(field, trace_data)
29
- context = set_current_resource(context_from_data(trace_data))
29
+ field = traced_field(trace_data)
30
+ auth_required = authenticate_option(field, trace_data)
31
+ context = context_from_data(trace_data)
30
32
 
31
- if !provided_value.nil?
32
- raise_on_missing_resource(context, field) if provided_value
33
- elsif @authenticate_default
34
- raise_on_missing_resource(context, field)
33
+ if context.key?(:resource_name)
34
+ ActiveSupport::Deprecation.warn(<<-DEPRECATION.strip_heredoc, caller)
35
+ Providing `resource_name` as part of the GQL context, or doing so by using the `graphql_context(resource_name)`
36
+ method on your controller is deprecated and will be removed in a future version of this gem.
37
+ Please use `gql_devise_context` in you controller instead.
38
+
39
+ EXAMPLE
40
+ include GraphqlDevise::Concerns::SetUserByToken
41
+
42
+ DummySchema.execute(params[:query], context: gql_devise_context(User))
43
+ DummySchema.execute(params[:query], context: gql_devise_context(User, Admin))
44
+ DEPRECATION
45
+ end
46
+
47
+ if auth_required && !(public_introspection && introspection_field?(field))
48
+ context = set_current_resource(context)
49
+ raise_on_missing_resource(context, field, auth_required)
35
50
  end
36
51
 
37
52
  yield
@@ -39,10 +54,13 @@ module GraphqlDevise
39
54
 
40
55
  private
41
56
 
57
+ attr_reader :public_introspection
58
+
42
59
  def set_current_resource(context)
43
- controller = context[:controller]
44
- resource_names = Array(context[:resource_name])
45
- context[:current_resource] = resource_names.find do |resource_name|
60
+ controller = context[:controller]
61
+ resource_names = Array(context[:resource_name])
62
+
63
+ context[:current_resource] ||= resource_names.find do |resource_name|
46
64
  unless Devise.mappings.key?(resource_name)
47
65
  raise(
48
66
  GraphqlDevise::Error,
@@ -57,8 +75,12 @@ module GraphqlDevise
57
75
  context
58
76
  end
59
77
 
60
- def raise_on_missing_resource(context, field)
78
+ def raise_on_missing_resource(context, field, auth_required)
61
79
  @unauthenticated_proc.call(field.name) if context[:current_resource].blank?
80
+
81
+ if auth_required.respond_to?(:call) && !auth_required.call(context[:current_resource])
82
+ @unauthenticated_proc.call(field.name)
83
+ end
62
84
  end
63
85
 
64
86
  def context_from_data(trace_data)
@@ -88,16 +110,13 @@ module GraphqlDevise
88
110
  end
89
111
 
90
112
  def authenticate_option(field, trace_data)
91
- if trace_data[:context]
113
+ auth_required = if trace_data[:context]
92
114
  field.metadata[:authenticate]
93
115
  else
94
116
  field.graphql_definition.metadata[:authenticate]
95
117
  end
96
- end
97
118
 
98
- def reconfigure_warden!
99
- Devise.class_variable_set(:@@warden_configured, nil)
100
- Devise.configure_warden!
119
+ auth_required.nil? ? @authenticate_default : auth_required
101
120
  end
102
121
 
103
122
  def load_fields
@@ -107,6 +126,10 @@ module GraphqlDevise
107
126
  resource_loader.call(@query, @mutation)
108
127
  end
109
128
  end
129
+
130
+ def introspection_field?(field)
131
+ INTROSPECTION_FIELDS.include?(field.name)
132
+ end
110
133
  end
111
134
  end
112
135
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GraphqlDevise
4
- VERSION = '0.14.0'.freeze
4
+ VERSION = '0.16.0'.freeze
5
5
  end
@@ -6,19 +6,30 @@ module Api
6
6
  include GraphqlDevise::Concerns::SetUserByToken
7
7
 
8
8
  def graphql
9
- result = DummySchema.execute(params[:query], execute_params(params))
9
+ result = DummySchema.execute(params[:query], **execute_params(params))
10
10
 
11
11
  render json: result unless performed?
12
12
  end
13
13
 
14
14
  def interpreter
15
- render json: InterpreterSchema.execute(params[:query], execute_params(params))
15
+ render json: InterpreterSchema.execute(params[:query], **execute_params(params))
16
16
  end
17
17
 
18
18
  def failing_resource_name
19
19
  render json: DummySchema.execute(params[:query], context: graphql_context([:user, :fail]))
20
20
  end
21
21
 
22
+ def controller_auth
23
+ result = DummySchema.execute(
24
+ params[:query],
25
+ operation_name: params[:operationName],
26
+ variables: ensure_hash(params[:variables]),
27
+ context: gql_devise_context(SchemaUser, User)
28
+ )
29
+
30
+ render json: result unless performed?
31
+ end
32
+
22
33
  private
23
34
 
24
35
  def execute_params(item)
@@ -2,9 +2,10 @@
2
2
 
3
3
  class DummySchema < GraphQL::Schema
4
4
  use GraphqlDevise::SchemaPlugin.new(
5
- query: Types::QueryType,
6
- mutation: Types::MutationType,
7
- resource_loaders: [
5
+ query: Types::QueryType,
6
+ mutation: Types::MutationType,
7
+ public_introspection: true,
8
+ resource_loaders: [
8
9
  GraphqlDevise::ResourceLoader.new(
9
10
  'User',
10
11
  only: [
@@ -5,6 +5,7 @@ module Types
5
5
  field :user, resolver: Resolvers::UserShow
6
6
  field :public_field, String, null: false, authenticate: false
7
7
  field :private_field, String, null: false, authenticate: true
8
+ field :vip_field, String, null: false, authenticate: ->(user) { user.is_a?(User) && user.vip? }
8
9
 
9
10
  def public_field
10
11
  'Field does not require authentication'
@@ -13,5 +14,9 @@ module Types
13
14
  def private_field
14
15
  'Field will always require authentication'
15
16
  end
17
+
18
+ def vip_field
19
+ 'Field available only for VIP Users'
20
+ end
16
21
  end
17
22
  end
@@ -11,7 +11,7 @@ Rails.application.routes.draw do
11
11
  }
12
12
 
13
13
  mount_graphql_devise_for(
14
- 'Admin',
14
+ Admin,
15
15
  authenticatable_type: Types::CustomAdminType,
16
16
  skip: [:sign_up, :check_password_token],
17
17
  operations: {
@@ -37,4 +37,5 @@ Rails.application.routes.draw do
37
37
  post '/api/v1/graphql', to: 'api/v1/graphql#graphql'
38
38
  post '/api/v1/interpreter', to: 'api/v1/graphql#interpreter'
39
39
  post '/api/v1/failing', to: 'api/v1/graphql#failing_resource_name'
40
+ post '/api/v1/controller_auth', to: 'api/v1/graphql#controller_auth'
40
41
  end
@@ -41,6 +41,5 @@ class CreateSchemaUsers < ActiveRecord::Migration[6.0]
41
41
  add_index :schema_users, [:uid, :provider], unique: true
42
42
  add_index :schema_users, :reset_password_token, unique: true
43
43
  add_index :schema_users, :confirmation_token, unique: true
44
- add_index :schema_users, :unlock_token, unique: true
45
44
  end
46
45
  end
@@ -0,0 +1,5 @@
1
+ class AddVipToUsers < ActiveRecord::Migration[6.1]
2
+ def change
3
+ add_column :users, :vip, :boolean, null: false, default: false
4
+ end
5
+ end
@@ -2,15 +2,15 @@
2
2
  # of editing this file, please use the migrations feature of Active Record to
3
3
  # incrementally modify your database, and then regenerate this schema definition.
4
4
  #
5
- # This file is the source Rails uses to define your schema when running `rails
6
- # db:schema:load`. When creating a new database, `rails db:schema:load` tends to
5
+ # This file is the source Rails uses to define your schema when running `bin/rails
6
+ # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
7
7
  # be faster and is potentially less error prone than running all of your
8
8
  # migrations from scratch. Old migrations may fail to apply correctly if those
9
9
  # migrations use external dependencies or application code.
10
10
  #
11
11
  # It's strongly recommended that you check this file into your version control system.
12
12
 
13
- ActiveRecord::Schema.define(version: 2020_06_23_003142) do
13
+ ActiveRecord::Schema.define(version: 2021_05_16_211417) do
14
14
 
15
15
  create_table "admins", force: :cascade do |t|
16
16
  t.string "provider", default: "email", null: false
@@ -73,7 +73,6 @@ ActiveRecord::Schema.define(version: 2020_06_23_003142) do
73
73
  t.text "tokens"
74
74
  t.datetime "created_at", precision: 6, null: false
75
75
  t.datetime "updated_at", precision: 6, null: false
76
- t.index "\"unlock_token\"", name: "index_schema_users_on_unlock_token", unique: true
77
76
  t.index ["confirmation_token"], name: "index_schema_users_on_confirmation_token", unique: true
78
77
  t.index ["email"], name: "index_schema_users_on_email", unique: true
79
78
  t.index ["reset_password_token"], name: "index_schema_users_on_reset_password_token", unique: true
@@ -106,6 +105,7 @@ ActiveRecord::Schema.define(version: 2020_06_23_003142) do
106
105
  t.datetime "created_at", null: false
107
106
  t.datetime "updated_at", null: false
108
107
  t.boolean "auth_available", default: true, null: false
108
+ t.boolean "vip", default: false, null: false
109
109
  t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
110
110
  t.index ["email"], name: "index_users_on_email", unique: true
111
111
  t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
@@ -33,7 +33,7 @@ RSpec.describe GraphqlDevise::InstallGenerator, type: :generator do
33
33
 
34
34
  assert_file 'app/controllers/application_controller.rb', /^\s{2}include GraphqlDevise::Concerns::SetUserByToken/
35
35
 
36
- assert_file 'app/graphql/gqld_dummy_schema.rb', /\s+#{Regexp.escape("GraphqlDevise::ResourceLoader.new('Admin')")}/
36
+ assert_file 'app/graphql/gqld_dummy_schema.rb', /\s+#{Regexp.escape("GraphqlDevise::ResourceLoader.new(Admin)")}/
37
37
  end
38
38
  end
39
39
 
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ RSpec.describe 'Users controller specs' do
6
+ include_context 'with graphql schema test'
7
+
8
+ let(:schema) { DummySchema }
9
+ let(:user) { create(:user, :confirmed) }
10
+ let(:field) { 'privateField' }
11
+ let(:public_message) { 'Field does not require authentication' }
12
+ let(:private_message) { 'Field will always require authentication' }
13
+ let(:private_error) do
14
+ {
15
+ message: "#{field} field requires authentication",
16
+ extensions: { code: 'AUTHENTICATION_ERROR' }
17
+ }
18
+ end
19
+
20
+ describe 'publicField' do
21
+ let(:query) do
22
+ <<-GRAPHQL
23
+ query {
24
+ publicField
25
+ }
26
+ GRAPHQL
27
+ end
28
+
29
+ context 'when using a regular schema' do
30
+ it 'does not require authentication' do
31
+ expect(response[:data][:publicField]).to eq(public_message)
32
+ end
33
+ end
34
+ end
35
+
36
+ describe 'privateField' do
37
+ let(:query) do
38
+ <<-GRAPHQL
39
+ query {
40
+ privateField
41
+ }
42
+ GRAPHQL
43
+ end
44
+
45
+ context 'when using a regular schema' do
46
+ context 'when user is authenticated' do
47
+ let(:resource) { user }
48
+
49
+ it 'allows to perform the query' do
50
+ expect(response[:data][:privateField]).to eq(private_message)
51
+ end
52
+
53
+ context 'when using a SchemaUser' do
54
+ let(:resource) { create(:schema_user, :confirmed) }
55
+
56
+ it 'allows to perform the query' do
57
+ expect(response[:data][:privateField]).to eq(private_message)
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ context 'when using an interpreter schema' do
64
+ let(:schema) { InterpreterSchema }
65
+
66
+ context 'when user is authenticated' do
67
+ let(:resource) { user }
68
+
69
+ it 'allows to perform the query' do
70
+ expect(response[:data][:privateField]).to eq(private_message)
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ describe 'user' do
77
+ let(:user_data) { { email: user.email, id: user.id } }
78
+ let(:query) do
79
+ <<-GRAPHQL
80
+ query {
81
+ user(
82
+ id: #{user.id}
83
+ ) {
84
+ id
85
+ email
86
+ }
87
+ }
88
+ GRAPHQL
89
+ end
90
+
91
+ context 'when using a regular schema' do
92
+ context 'when user is authenticated' do
93
+ let(:resource) { user }
94
+
95
+ it 'allows to perform the query' do
96
+ expect(response[:data][:user]).to match(**user_data)
97
+ end
98
+ end
99
+ end
100
+
101
+ context 'when using an interpreter schema' do
102
+ let(:schema) { InterpreterSchema }
103
+
104
+ context 'when user is authenticated' do
105
+ let(:resource) { user }
106
+
107
+ it 'allows to perform the query' do
108
+ expect(response[:data][:user]).to match(**user_data)
109
+ end
110
+ end
111
+
112
+ context 'when user is not authenticated' do
113
+ # Interpreter schema fields are public unless specified otherwise (plugin setting)
114
+ it 'allows to perform the query' do
115
+ expect(response[:data][:user]).to match(**user_data)
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end